บทนำ (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”
<?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)
<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)
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” ดังนี้
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” ที่เราอนุญาต
<?php //header( 'X-Frame-Options: SAMEORIGIN' ); header("X-Frame-Options: ALLOW-FROM http://172.16.112.133"); ?>
- เมื่อลองดัก “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”
<?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”
<?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”
192.168.0.16 - เราสามารถกำหนดเป็น “White-list” สำหรับ “ip” หรือ “domain” ที่อนุญาตให้ “iframe” ถึงหน้าหรือข้อมูลของเราไปใช้ได้ ดังนี้
<?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+ header("Content-Security-Policy: frame-ancestors http://192.168.0.16 http://172.16.112.133"); ?>
- ทดสอบลองเข้าหน้า (172.16.112.133) อีกครั้งสามารถดึงข้อมูลโดยใช้ “iframe” ตาม “URL” ที่กำหนด
192.168.0.16