By:Mirror王宇陽javascript
XSS攻擊是指在網頁中嵌入一段惡意的客戶端Js腳本代碼片斷,JS腳本惡意代碼能夠獲取用戶的Cookie、URL跳轉、內容篡改、會話劫持……等。php
xss攻擊手段自己對服務端沒有直接的危害,xss主要是藉助網站傳播;通常經過留言板、郵件、等其餘途徑向受害者發送一段惡意的URL,受害者經過訪問該惡意URL可能會致使惡意的xss腳步會在受害者的客戶端瀏覽器中執行,實現本身的目的html
XSS的攻擊類別分爲:反射型、存儲型、DOM型等三大類攻擊類別。前端
反射型XSS會把用戶輸入的數據直接返回給頁面,是一種非持久型攻擊;這類型的xss是最爲常見的,主要的利用方法就是惡意腳本添加到參數(URL)發送給用戶誘騙用戶點擊後反射數據給頁面。java
頁面源碼mysql
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>XSS | 反射型</title> </head> <body> <form action="xss.php" method="GET"> <h2>xss反射型注入攻擊測試</h2> <span>測試語句:</span> <input type="text" name="name"> <input type="submit" value="提交"> </form> </body> </html>
後臺源碼web
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Text page | Return</title> </head> <body> <h2>反射型測試頁面</h2> <?php echo $_GET["name"]; ?> </body> </html>
源碼分析sql
咱們輸入的內容會被執行並嵌入在HTML頁面中;$_GET['name']會觸發js惡意代碼並嵌入HTML頁面中。數據庫
測試express
XSS測試
結果發現:咱們在輸入text框中寫入了一個Js代碼,代碼直接被執行並嵌入在HTML頁面中;衆所周知,Js代碼和HTML代碼直接暴露在客戶端,一旦寫入的Js代碼能夠被執行並嵌入在HTML頁面中即視爲存在XSS攻擊。
惡意利用
咱們經過向受害者發送以下的惡意URL就能夠實如今用戶客戶端執行該惡意js腳本;
http://127.0.0.1/xss/xss.php?name=<script>alert('XSS測試結果');</script>
攻擊者還會將URL進行各式各樣的加密轉換的處理,最大程度的減小URL惡意腳本的暴露;
存儲型XSS是一種持久的xss攻擊類別,攻擊者將惡意腳本植入到服務端數據庫或長期的嵌入在HTML頁面中;當用戶符合觸發條件後就會觸發Js的xss惡意腳本。
存儲型的xss一般會存儲在客戶端或數據庫中,當用戶訪問頁面即觸發xss。
存儲型的xss不須要構造URL誘騙用戶去點擊,大大的減小暴露和增長隱祕性。
建立數據庫和表
create table text( uid int(10) not null auto_increment primary key, title varchar(20) null, content text(100) null )engine=innodb default charset=utf8;
HTML頁面源碼
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>xss | 存儲型</title> </head> <body> <form action="xss_storage.php" method="POST"> <span> <h2>xss|存儲型測試</h2> <h3>留言板測試</h3> </span> 主題:<input type="text" name="title"></br> 留言:<textarea name="content"> </textarea><!-- 文本域留言 --> <input type="submit" name="提交"> </form> </body> </html>
PHP後臺源碼
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>xss | 存儲型</title> </head> <body> <!-- create databases xss_text 建立數據庫--> <?php $conn = mysqli_connect("127.0.0.1","root","root","xss_text") or die("數據庫鏈接錯誤".mysqli_error()); // set names utf-8 -- 寫入數據庫採用的編碼(utf-8) mysqli_query($conn, 'set names utf-8'); if (isset($_POST["title"])) { $title = $_POST["title"]; $content = $_POST["content"]; //向數據庫添加 title content 兩字段的內容 $sql = "INSERT INTO `xss_text`.`text` (`uid`, `title`, `content`) VALUES (NULL, '$title', '$content')"; echo $sql; $result_1 = mysqli_query($conn,$sql); // 頁面回顯/查詢數據 $result_2 = mysqli_query($conn , "select * from text"); echo "<table boreder='1'><tr><td>標題</td><td>內容</td></tr>"; while($row = mysqli_fetch_array($result_2, MYSQLI_BOTH)) { echo "<tr><td>" . $row['title']. "</td><td>" .$row['content']. "</td>"; } echo "</table>"; echo $row['title']; } ?> </body> </html>
分析
當用戶在content寫入一個可執行惡意js腳本的標籤便可過程xss例如:<input type="button" value="xss" onclick="alert(xss)"/>
,提交查詢後內容就會寫入在數據庫中,在數據庫的查詢結果回顯至頁面後就能夠觸發了,這裏舉兩個例子,一個是手動觸發,一個是自動加載觸發。
測試
這是寫入一個input標籤,鼠標點擊事件可執行一個js腳本即一個彈窗。
這裏是寫入了一個img標籤可是標籤src無索引會錯誤error,由此觸發onerror屬性執行js;也可使用其餘相似於onload屬性……
測試過程當中發現單引號沒法存入數據庫,緣由本小白也是半懂不懂;在sql執行的寫入的時候單引號會被轉義,對此能夠嘗試雙單引號來實現最後也會以單引號的語句保存在表中。
基於DOM的XSS攻擊手段,效果上和反射型XSS相似;經過修改頁面的DOM節點造成XSS。
DOM規定:
節點與節點之間都有等級關係
測試源碼
<!DOCTYPE html> <head> <meta charset='utf-8'> <title>xss | DOM</title> </head> <body> <h1> XSS - DOM攻擊測試頁面 </h1> <script type="text/javascript"> function xss() { var str = document.getElementById("xss").value; document.getElementById("demo").innerHTML = "<a href = '"+str+"'>超連接</a>"; } </script> <div id = "demo"> 測試區域 </div> <div> xss測試: <input type="text" id="xss" /> <input type="button" id="a" value="提交" onclick="xss()" /> </div> </body>
分析
當咱們想id=xss提交數據後,提交的內容則會做爲a標籤的href屬性被寫入在HTML頁面中;而攻擊者則採用閉合拼接的方式來構成惡意的xss
測試
構造惡意的閉合xss
<a href = "" onclick=alert("Hello,World!") >超連接</a> xss 提交: " onclick=alert("Hello,World!")
這樣的xss構造語句會向測試區域發送惡意的構造標籤實現攻擊目的
<script> alert(1) </script> <img src=x onerror = alert(1) /> <svg onload=alert(1)> <a href=javascript:alert(1)>
JS提供了四種字符編碼的策略
\***
\x**
\u****
控制字符,例如 \r , \h , \t
HTML實體編碼
命名實體:命名以 「&」 開頭,分號結尾;參考:實體編碼字符
字符編碼:十進制、十六進制ASCII編碼或Unicode字符編碼
在線工具:http://tool.chinaz.com/tools/urlencode.aspx
線下工具:URL編碼解碼工具(Burp-Decoder)
使用手動檢測能夠最大精確化,可是對於大型的web應用是困難的是;最首要的重要就是哪裏有輸入、輸入的結果輸出的地方。
手工檢測XSS要使用特殊意義的字符,這樣能夠快速的測試是否存在XSS;
可得知輸出位置
輸入一些敏感字符,例如: > < " ' ( )等,遵守自提交後查看HTML源代碼,查看本身輸入的字符是否被轉義;
沒法得知輸出位置
大多的web應用時非開源的,測試XSS的時候沒法得知具體的輸出位置顯示;例如:咱們的評論提交後會交由後臺進行內容敏感檢查,咱們就沒法得知具體的輸出位置了;
<input type="text" id="name" value="Coke" />
上述是一個表單,咱們可使用/> xxx
測試該標籤的具體輸出位置
Cookie時可以讓網站服務器吧少許的文本數據存儲到客戶端的硬盤或內存中,用於維持HTTP無狀態協議致使的可持續網站會話;
如何產生:
當咱們訪問某網站,網站服務端因爲HTTP時無狀態協議,而客戶端和服務器沒法直接判斷是否來自同一個客戶源,爲此當用戶訪問第一次網站後並登陸等操做,服務端會返回Cookie給客戶端的硬盤或內存中存留
如何使用:
當用戶第二次訪問服務端的時候,服務端就會檢查客戶端中是否有Cookie文件,若是有Cookie則會利用該文件登陸並訪問網站
Cookie格式:
每個瀏覽器保存的Cookie的文件位置均不一樣,這裏以Firefox瀏覽器爲例,咱們訪問DVWA平臺並登陸,保存用戶和密碼造成Cookie
Cookie主要由變量名key和值value組成:
Set-Cookie: <name>=<value>[;<Max-Age>=<age>][;expires=<date>][;domain=<domain_name>][;path=<some_path>][;secure][;HttpOnly]
Set-Cookie
HTTP服務器的響應頭,Web服務器經過此頭講Cookie發給客戶端
name=value
Cookie必有部分,用戶經過name取得Cookie的對應的Value值
expires=<date>
規定了Cookie的有效終止日期;缺省該字段則cookie不會存儲在硬盤中
domain=<domain_name>
規定了哪些Internet域中的Web服務器能夠讀取客戶端的Cookie文件,若是缺省則Web服務器的域名爲Value;
path=<some_path>
定義Web服務器上哪些路徑下的頁面能夠獲取服務器發送的Cookie文件;Value爲/
表示Web服務器中全部頁面均可以獲取Cookie文件;若是缺省,Path的Value則是Web服務器向客戶端發送Cookie的URL;
Secure
Cookie中標明變量,只有當web服務器和客戶端之間採用HTTPS加密認證協議才能夠進行鏈接通訊提交Cookie文件
HttpOnly
禁止JavaScript讀取
Cookie中的內容通過加密處理,只有Web服務器的Cookie處理程序能夠解析Cookie真正的意義
利用xss獲取cookie
建立一個cookie
setcookie()
函數向客戶端發送一個 HTTP cookie。參考文章
setcookie(name,value,expire,path,domain,secure) # 參數定義 name 必需。規定 cookie 的名稱。 value 必需。規定 cookie 的值。 expire 可選。規定 cookie 的有效期。 如果刪除一個cookie則能夠設置時間爲過去時 path 可選。規定 cookie 的服務器路徑。 domain 可選。規定 cookie 的域名。 secure 可選。規定是否經過安全的 HTTPS 鏈接來傳輸 cookie。 註釋:能夠經過 $HTTP_COOKIE_VARS["user"] 或 $_COOKIE["user"] 來訪問名爲 "user" 的 cookie 的值。 註釋:在發送 cookie 時,cookie 的值會自動進行 URL 編碼。接收時會進行 URL 解碼。若是你不須要這樣,可使用 setrawcookie() 代替。
頁面添加設置COOKIE
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>XSS | 反射型</title> </head> <body> <form action="xss.php" method="GET"> <h2>xss反射型注入攻擊測試</h2> <span>測試語句:</span> <input type="text" name="name"> <input type="submit" value="提交"> </form> <?php $COOKIE="XSS獲取COOKIE測試"; setcookie("xss_cookie",$COOKIE); echo "COOKIE設置成功"; ?> </body> </html>
xss獲取Cookie
<script> alert(document.cookie);//獲取Cookie </script>
惡意構造URL
http://127.0.0.1/xss/xss.php?name=<script>alert(document.cookie);</script>
如果用戶訪問了這個URL則會直接暴露本身的COOKIE,一旦暴露,攻擊者能夠僞造COOKIE訪問。
COOKIE安全
正是由於Cookie存在客戶端且能夠容易被僞造,因此最初的預防辦法就是高度加密;用戶獲取Cookie信息後僞造Cookie登陸便可操做該帳號。對於高度加密的COOKIE攻擊者至於要原樣僞造一個便可,由於解密的大可能是在服務端解密Cookie的;Cookie被竊取後就會致使Cookie僞造會話/Cookie欺騙嚴重的安全漏洞。
輸入過濾
永遠不要相信用戶的輸入;通常狀況在客戶端要設置字符驗證過濾敏感的字符、限制長度、要求格式……等。固然客戶端的內容用戶都是可控的,單單依靠客戶端是不可靠的,經過Burp等工具,能夠輕易的修改數據包,繞過 客戶端的過濾檢查。
輸出轉碼
千萬不要把用戶的輸入內容完整的回顯至HTML頁面中!通常使用HTMLEncode進行編碼處理。
htmlspecialchars()函數能夠將部分特殊字符轉出HTML實體編碼。
<?php echo htmlentities($_GET["name"]); // echo $_GET["name"]; ?>
輸出的轉碼能夠預防xss腳本直接回顯執行
黑名單
使用黑名單和白名單對輸入的內容進行正則匹配,不符合的則不執行並取消。開發人員將敏感的關鍵詞 、特殊字符進行黑名單設置,將一些符合條件的字符、關鍵詞歸入白名單。
前端過濾函數
function xss_clean($data){ // Fix &entity\n; $data=str_replace(array('&','<','>'),array('&','<','>'),$data); $data=preg_replace('/(&#*\w+)[\x00-\x20]+;/u','$1;',$data); $data=preg_replace('/(&#x*[0-9A-F]+);*/iu','$1;',$data); $data=html_entity_decode($data,ENT_COMPAT,'UTF-8'); // Remove any attribute starting with "on" or xmlns $data=preg_replace('#(<[^>]+?[\x00-\x20"\'])(?:on|xmlns)[^>]*+>#iu','$1>',$data); // Remove javascript: and vbscript: protocols $data=preg_replace('#([a-z]*)[\x00-\x20]*=[\x00-\x20]*([`\'"]*)[\x00-\x20]*j[\x00-\x20]*a[\x00-\x20]*v[\x00-\x20]*a[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iu','$1=$2nojavascript...',$data); $data=preg_replace('#([a-z]*)[\x00-\x20]*=([\'"]*)[\x00-\x20]*v[\x00-\x20]*b[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iu','$1=$2novbscript...',$data); $data=preg_replace('#([a-z]*)[\x00-\x20]*=([\'"]*)[\x00-\x20]*-moz-binding[\x00-\x20]*:#u','$1=$2nomozbinding...',$data); // Only works in IE: <span style="width: expression(alert('Ping!'));"></span> $data=preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?expression[\x00-\x20]*\([^>]*+>#i','$1>',$data); $data=preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?behaviour[\x00-\x20]*\([^>]*+>#i','$1>',$data); $data=preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:*[^>]*+>#iu','$1>',$data); // Remove namespaced elements (we do not need them) $data=preg_replace('#</*\w+:\w[^>]*+>#i','',$data); do{// Remove really unwanted tags $old_data=$data; $data=preg_replace('#</*(?:applet|b(?:ase|gsound|link)|embed|frame(?:set)?|i(?:frame|layer)|l(?:ayer|ink)|meta|object|s(?:cript|tyle)|title|xml)[^>]*+>#i','',$data); }while($old_data!==$data); // we are done... return $data; }
後端過濾
<?php //php防注入和XSS攻擊通用過濾. //by qq:831937 $_GET && SafeFilter($_GET); $_POST && SafeFilter($_POST); $_COOKIE && SafeFilter($_COOKIE); function SafeFilter (&$arr) { $ra=Array('/([\x00-\x08,\x0b-\x0c,\x0e-\x19])/','/script/','/javascript/','/vbscript/','/expression/','/applet/','/meta/','/xml/','/blink/','/link/','/style/','/embed/','/object/','/frame/','/layer/','/title/','/bgsound/','/base/','/onload/','/onunload/','/onchange/','/onsubmit/','/onreset/','/onselect/','/onblur/','/onfocus/','/onabort/','/onkeydown/','/onkeypress/','/onkeyup/','/onclick/','/ondblclick/','/onmousedown/','/onmousemove/','/onmouseout/','/onmouseover/','/onmouseup/','/onunload/'); if (is_array($arr)) { foreach ($arr as $key => $value) { if (!is_array($value)) { if (!get_magic_quotes_gpc())//不對magic_quotes_gpc轉義過的字符使用addslashes(),避免雙重轉義。 { $value = addslashes($value); //給單引號(')、雙引號(")、反斜線(\)與NUL(NULL字符)加上反斜線轉義 } $value = preg_replace($ra,'',$value); //刪除非打印字符,粗暴式過濾xss可疑字符串 $arr[$key] = htmlentities(strip_tags($value)); //去除 HTML 和 PHP 標記並轉換爲HTML實體 } else { SafeFilter($arr[$key]); } } } } ?>
防止xss竊取Cookie可使用HttpOnlyCookie;
當一個Cookie在Set-cookie消息頭中被標明爲HttpOnly時,客戶端的js是不能夠直接訪問該cookie的。
PHP設置HttpOnly
修改php.ini文件,設置session.cookie_httponly =1
setcookie()函數和setrawcookie()函數的第七個參數用來作HttpOnly啓動選項
setcookie('','','','','','',TRUE); setrawcookie('','','','','','',TRUE);
php代碼開啓HttpOnly
<?php ini_set("session.cookie_httponly",1); session_set_cookie_params(0,null,null,null,TRUE) ?>
用戶在訪問網站的時候爲了防止惡意腳本在本身的客戶端上唄執行,也能夠在瀏覽器上安裝一個插件,利用插件的功能來禁止頁面的腳本執行。