How to defend against Clickjacking (PHP)

บทนำ (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

  1.  สร้างหน้า “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>
    
  2. นำไปใส่ใน “Web server” หลัก (192.168.0.16)
  3. ทดสอบลองเรียกหน้าดังกล่าวจาก เครื่องอื่น (172.16.112.133) พบว่าสามารถเข้าหน้า “Login” ได้xframe01
  4. สร้างหน้าสำหรับเรียกใช้ “iframe” และ นำไปใส่ที่ “Web server” หลัก (192.168.0.16)
    <iframe src="http://192.168.0.16/pentest/testOT.php"  width="1100" height="700" border="0" /></iframe>
    
  5. เมื่อลองดัก “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
    
  6. ทดสอบลองเรียกหน้าดังกล่าวจาก เครื่องอื่น (172.16.112.133) พบว่ายังสามารถเข้าหน้า “Login” ได้ (มีกรอบของ iframe ปรากฏอยู่) xframe02
  7. ที้นี้สุดท้ายเอาไฟล์ของข้อ (4) นำไปใส่ที่ “Web server” ที่จะทำ Click-jacking (172.16.112.133) พบว่าไม่สามารถดึงหน้าได้ จะได้หน้าขาว ๆ ดังรูปxframe03
  8. จากข้อ (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

  1. จากหน้า “Login” ของ “SAMEORIGIN” ให้เปลี่ยนเป็น “Source” ที่เราอนุญาต
    <?php
    //header( 'X-Frame-Options: SAMEORIGIN' );
    header("X-Frame-Options: ALLOW-FROM http://172.16.112.133");
    ?>
    
  2. เมื่อลองดัก “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
    
  3. ลองทดสอบตาม (7) ข้างต้นอีกครั้งพบว่าเว็บไซต์นี้สามารถดึงหน้า “Login” ได้ xframe04

DENY

  1. จากหน้า “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");
    ?>
    
  2. เมื่อลองดัก “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
    
  3. ที่นี้ลองทดสอบการเรียก “iframe” จาก “ip” เดียวกันตามข้อ (6) ข้างต้น จะพบว่าก็ไม่สามารถดึงหน้า “Login” ได้แล้ว xframe05

PHP – Content-Security-Policy

  1. เราสามารถใช้ “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");
    ?>
    
  2. เมื่อลองดัก “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
    
  3. ลองใช้ “iframe” ดึงข้อมูล โดย “iframe” จาก ip (192.168.0.16) คือ Self และ ip (172.16.112.133) คือ “clickjacking”
    xframe02
    192.168.0.16

    xframe06
    172.16.112.133
  4. เราสามารถกำหนดเป็น “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");
    ?>
    
  5. ทดสอบลองเข้าหน้า (172.16.112.133) อีกครั้งสามารถดึงข้อมูลโดยใช้ “iframe” ตาม “URL” ที่กำหนด
    xframe02
    192.168.0.16

    xframe04
    172.16.112.133

ใส่ความเห็น