บทนำ (Overview)
จากบทความ (How to demonstrate ClickJacking with Jack) เราสามารถป้องกันการโจมตี “Click-jacking” ได้โดยโดยใช้ “X-Frame-Option” หรือ “Content-Security-Policy” โดยหลักการคือทาง “Server” เราจะต้อง “Set” ให้สามารถส่ง “Header” และค่าที่ต้องการไปยัง “Web Browser” และจากนั้น “Web Browser” จะประมวลผลเองว่าจะให้แสดงหรือไม่แสดงข้อมูลใน <iframe> ได้หรือไม่
โดยหลัก แต่ละค่ามีความหมายดังต่อไปนี้
- DENY: เว็บไซต์ที่ใช้ <iframe> จะไม่ถูกแสดงข้อมูล
- SAMEORIGIN: เว็บไซต์ทีมี “URL” หรือ “Domain” หรือ “IP” เดียวกันจะสามารถแสดงข้อมูลใน <iframe> ได้ถ้าต่างกันข้อมูลใน <iframe> จะไม่แสดงผล
- ALLOW-FROM: เว็บไซต์ที่กำหนดไว้ จะสามารถแสดงข้อมูลใน <iframe> ได้
ขั้นตอน (Steps)
PHP – X-Frame-Options
SAMEORIGIN
- สร้างหน้า “Login” สำหรับตัวอย่าง และตั้งค่าเป็น “SAMEORIGIN”
12345678910111213141516171819202122
<?php
header(
'X-Frame-Options: SAMEORIGIN'
);
?>
<table>
<tr>
<th>Please login...</th>
</tr>
<tr>
<td>Username</td>
<td><input type=
"text"
></td>
</tr>
<tr>
<td>Password</td>
<td><input type=
"password"
></td>
</tr>
<tr>
<td></td>
<td><input type=
"submit"
value=
"Login"
></td>
</tr>
</table>
- นำไปใส่ใน “Web server” หลัก (192.168.0.16)
- ทดสอบลองเรียกหน้าดังกล่าวจาก เครื่องอื่น (172.16.112.133) พบว่าสามารถเข้าหน้า “Login” ได้
- สร้างหน้าสำหรับเรียกใช้ “iframe” และ นำไปใส่ที่ “Web server” หลัก (192.168.0.16)
1
<
iframe
src
=
"http://192.168.0.16/pentest/testOT.php"
width
=
"1100"
height
=
"700"
border
=
"0"
/></
iframe
>
- เมื่อลองดัก “Response Message” พบว่ามี “Header” ชื่อ “X-Frame-Options” เกิดขึ้น (สามารถใช้คำสั่ง “curl” ใน “Kali” หรือใช้ “Burp” เพื่อดัก “Response message” – http://blog.itselectlab.com/?p=3569)
12345678
root@kali:~
# curl -I http://172.20.10.13/pentest/testOT.php
HTTP
/1
.1 200 OK
Date: Thu, 06 Aug 2015 06:22:13 GMT
Server: Apache
/2
.2.22 (Debian)
X-Powered-By: PHP
/5
.4.36-0+deb7u3
X-Frame-Options: SAMEORIGIN
Vary: Accept-Encoding
Content-Type: text
/html
- ทดสอบลองเรียกหน้าดังกล่าวจาก เครื่องอื่น (172.16.112.133) พบว่ายังสามารถเข้าหน้า “Login” ได้ (มีกรอบของ iframe ปรากฏอยู่)
- ที้นี้สุดท้ายเอาไฟล์ของข้อ (4) นำไปใส่ที่ “Web server” ที่จะทำ Click-jacking (172.16.112.133) พบว่าไม่สามารถดึงหน้าได้ จะได้หน้าขาว ๆ ดังรูป
- จากข้อ (7) ถึงแม้จะไม่แสดงข้อมูล แต่ข้อมูลก็ยังส่งมาที่ “Browser” ดังนี้
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950
HTTP/1.1 200 OK
Date: Thu, 06 Aug 2015 04:32:31 GMT
Server: Apache/2.2.22 (Debian)
X-Powered-By: PHP/5.4.36-0+deb7u3
X-Frame-Options: ALLOW-FROM http://172.16.112.133
Vary: Accept-Encoding
Content-Length: 301
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: text/html
<
table
>
<
tr
>
<
th
>
Please login...
</
th
>
</
tr
>
<
tr
>
<
td
>
Username
</
td
>
<
td
>
<
input
type
=
"text"
>
</
td
>
</
tr
>
<
tr
>
<
td
>
Password
</
td
>
<
td
>
<
input
type
=
"password"
>
</
td
>
</
tr
>
<
tr
>
<
td
>
</
td
>
<
td
>
<
input
type
=
"submit"
value
=
"Login"
>
</
td
>
</
tr
>
</
table
>
ALLOW-FROM
- จากหน้า “Login” ของ “SAMEORIGIN” ให้เปลี่ยนเป็น “Source” ที่เราอนุญาต
1234
<?php
//header( 'X-Frame-Options: SAMEORIGIN' );
?>
- เมื่อลองดัก “Response Message” พบว่ามี “Header” ชื่อ “X-Frame-Options” เกิดขึ้น โดยมี URL ที่เราอนุุญาตกำหนดมาด้วย
HTTP/1.1 200 OK Date: Wed, 05 Aug 2015 16:42:55 GMT Server: Apache/2.2.22 (Debian) X-Powered-By: PHP/5.4.36-0+deb7u3 X-Frame-Options: ALLOW-FROM http://172.16.112.133 Vary: Accept-Encoding Content-Length: 301 Content-Type: text/html
- ลองทดสอบตาม (7) ข้างต้นอีกครั้งพบว่าเว็บไซต์นี้สามารถดึงหน้า “Login” ได้
DENY
- จากหน้า “Login” ลองเปลี่ยน “Header” เป็น “DENY”
123456
<?php
// Firefox 3.6.9+, Chrome 4.1+, IE 8+, Safari 4+, Opera 10.5+
//header( 'X-Frame-Options: SAMEORIGIN' );
//header("X-Frame-Options: ALLOW-FROM http://172.16.112.133");
header(
"X-Frame-Options: DENY"
);
?>
- เมื่อลองดัก “Response Message” พบว่ามี “Header” ชื่อ “X-Frame-Options” เกิดขึ้น และสังเกตุว่ามีค่าเป็น “DENY”
HTTP/1.1 200 OK Date: Wed, 05 Aug 2015 16:55:17 GMT Server: Apache/2.2.22 (Debian) X-Powered-By: PHP/5.4.36-0+deb7u3 X-Frame-Options: DENY Vary: Accept-Encoding Content-Length: 301 Content-Type: text/html
- ที่นี้ลองทดสอบการเรียก “iframe” จาก “ip” เดียวกันตามข้อ (6) ข้างต้น จะพบว่าก็ไม่สามารถดึงหน้า “Login” ได้แล้ว
PHP – Content-Security-Policy
- เราสามารถใช้ “Content-Security-Policy” ได้เช่นเดียวกับ “X-Frame-Options” ดังนี้ (ทดลองใช้ self ซึ่งผลลัพท์ คือ “SAMEORIGIN”
1234567891011121314
<?php
//header( 'X-Frame-Options: SAMEORIGIN' );
//header("X-Frame-Options: ALLOW-FROM http://172.16.112.133");
//header("X-Frame-Options: DENY");
//DENY
//header("Content-Security-Policy: frame-ancestors 'none'");
//SAMEORIGIN
header(
"Content-Security-Policy: frame-ancestors 'self'"
);
//ALLOW-FROM White-Lists
//header("Content-Security-Policy: frame-ancestors http://192.168.0.16 http://172.16.112.133");
?>
- เมื่อลองดัก “Response Message” พบว่ามี “Header” ชื่อ “Content-Security-Policy” เกิดขึ้น
HTTP/1.1 200 OK Date: Wed, 05 Aug 2015 18:38:51 GMT Server: Apache/2.2.22 (Debian) X-Powered-By: PHP/5.4.36-0+deb7u3 Content-Security-Policy: frame-ancestors 'self' Vary: Accept-Encoding Content-Length: 301 Content-Type: text/html
- ลองใช้ “iframe” ดึงข้อมูล โดย “iframe” จาก ip (192.168.0.16) คือ Self และ ip (172.16.112.133) คือ “clickjacking”
- เราสามารถกำหนดเป็น “White-list” สำหรับ “ip” หรือ “domain” ที่อนุญาตให้ “iframe” ถึงหน้าหรือข้อมูลของเราไปใช้ได้ ดังนี้
123456789101112131415
<?php
//header( 'X-Frame-Options: SAMEORIGIN' );
//header("X-Frame-Options: ALLOW-FROM http://172.16.112.133");
//header("X-Frame-Options: DENY");
//DENY
//header("Content-Security-Policy: frame-ancestors 'none'");
//SAME ORIGIN
//header("Content-Security-Policy: frame-ancestors 'self'");
//ALLOW-FROM White-Lists
//Firefox 23+, Chrome 25+, Safari 7+, Opera 19+
?>
- ทดสอบลองเข้าหน้า (172.16.112.133) อีกครั้งสามารถดึงข้อมูลโดยใช้ “iframe” ตาม “URL” ที่กำหนด