什麼是 XSS 攻擊?如何防範?

2025年12月24日

💎 加入 E+ 成長計畫 與超過 900+ 位工程師一同在社群成長,並獲得更多深度的軟體前後端學習資源

XSS (cross-site scripting) 是很常見的網路攻擊。身為網頁前端或後端工程師,在面試中,很常會問到 XSS 的問題,因為面試官要確定你對於 XSS 的基本概念需要有所掌握。

什麼是 XSS?

所謂的 XSS (cross-site scripting) 攻擊,指當某個攻擊者成功讓惡意腳本程式碼被注入到「網站輸出的內容」中,導致該程式碼在其他使用者的瀏覽器上、以該網站的身分被執行,就好像這段腳本原本就屬於該網站一樣。

對瀏覽器而言,因為這段程式碼看起來是從該網站發出的,瀏覽器會給予完整的權限去存取該網站的所有資源 (包括 Cookie、Session Token 等敏感資訊),進而造成嚴重的問題。

如果想了解可以輸入什麼樣的惡意 Javascript 語法,讓系統出現問題,可以透過這個 網站 來試試看。

因為 JavaScript 幾乎可以做到任何事,所以 XSS 的攻擊能做到的事情也是五花八門。舉例來說,竊取別的用戶的 cookie,然後透過拿到的 cookie 來發送請求;或者是竄改網頁內容。

下面分享一個早些年直播平台 Twitch 因為防禦做得不夠完善,被惡搞的例子,就是透過 XSS 達成的。有網友會在 Twitch 直播留言帶有惡搞性質的程式碼,來把直播間搞亂。因為該留言會被渲染到其他使用者的頁面中,所以瀏覽器也會執行該留言中的惡搞程式碼腳本,讓所有觀看直播的網友都會被波及到。

近年來著名的 XSS 攻擊案例之一,是《how to hack discord, vercel and more with one easy trick》一文所揭露的。

這個漏洞之所以會被發現,是因為前陣子 Discord 宣布把開發者文件,由自建的平台,改成用 Mintlify 來託管;由於這幾位白帽駭客平常就是用 Discord 來交流,所以這個遷移讓他們起了對 Mintlify 平台的興趣。

在探索一番後,他們發現 Mintlify 在所有文件網站底下,都暴露了一個 /mintlify/static/[subdomain]/... 的路徑,用來讀取文件庫裡的靜態資產,例如圖片、SVG 等等。

在看到這個路徑時,他們思考到「不知該端點會不會確認所在的網域?」,結果試了一下發現還真的沒有確認。這代表假如自己辦一個 Mintlify 的帳號,然後上傳 SVG 檔案到自己的 Mintlify 帳號,然後透過 Discord 的網域來存取該 SVG 檔案。

該白帽駭客實際嘗試,上傳了一張帶有惡意腳本的 xss.svg 到自己的 evascoolcompany 帳號,然後再到 https://discord.com/mintlify/static/evascoolcompany/xss.svg 網址中,結果該惡意 JavaScript 腳本真的被執行了。

這種漏洞又被稱為單次點擊 XSS 攻擊 (one-click XSS),攻擊者只需要誘使受害者點擊一個看似正常的連結,就能在受害者的瀏覽器中執行任意程式碼。

舉例來說,你以為你點了一個看起來像 Discord 官方文件的連結,但實際上瀏覽器就會在 discord.com 這個網域下執行攻擊者的程式碼,讓 localStorage、token、登入狀態,全部都能被竊取。

XSS 攻擊的類型

Stored XSS

被保存在資料庫中的 Javascript 引起的攻擊稱為 Stored XSS,最常見的就是文章、留言等,因為用戶可以任意輸入內容,若沒有檢查,則 <script> 等標籤就會被視為正常的 HTML 做執行。

Reflected XSS

此類型不會被存在資料庫中,主要透過用戶發出惡意的請求,倘若後端沒有過濾而直接將結果回傳前端的話,就有可能執行到惡意的程式碼,舉例來說:

Reflected XSS
Reflected XSS

倘若用戶填完名字後,顯示的程式碼如下:

<h3> Hi, <?=$_GET['name'] ?> </h3>

則很有可能被用戶惡意填寫為:

https://websiteA/welcome?name=<script>alert(123)</script>

此種手法通常都用於釣魚、社交工程等方式誘騙用戶點入連結。

DOM-Based XSS

DOM 全名為 Document Object Model,它可以利用 Javascript 動態產生完整的網頁,不用透過後端,因此 DOM-Based XSS 是指網頁上的 Javascript 在執行過程中,沒有檢查輸入資料,使得操作 DOM 的過程中帶入了惡意程式碼。

DOM-Based XSS
DOM-Based XSS

在同一個網址上,透過 DOM 的方式直接顯示在前端頁面

<script>
  var hello = function () {
    let name = document.getElementById("name").value;
    document.getElementById("show").innerHTML = name;
  };
</script>
<h3>Hi, <span id="show"></span></h3>
<input id="name" type="text" />
<button onclick="hello();">Go</button>

因此只要將輸入的內容寫為

<img src="#" onerror="alert(123);" />

則會因為讀取不出圖片而產生錯誤,觸發 onerror ,並執行 alert(123)

此類型的攻擊,或許沒辦法直接讓用戶輸入語法,但可以搭配 Stored XSS 和 Reflected XSS 製造出內容,再藉由 Javascript 動態產生有效的 DOM 物件來執行惡意程式碼。

如何防禦 XSS?

  1. DOM-Based 防範 - 檢查輸入欄位。此攻擊需要從前端去防範,任何的輸入欄位,例如留言欄位、檔案上傳欄位、表單的欄位等,都要有跳脫的機制,讓腳本被轉換成字符串。舉例來說,如果攻擊者輸入 <script>alert(1)</script> ,我們把 < 轉成 &lt ,在畫面上依然是呈現 < 但是對程式來說,它不會被當成 HTML 標籤來解析。

  2. 確保來自使用者的腳本不會被執行。透過 CSP (content security policy) 來設定有哪些網域 (domains) 來的腳本該被瀏覽器認為是該被執行的,然後瀏覽器只執行那些該被執行的腳本。舉例來說,如果設定只有來自與網站同一個網域的腳本可被執行,那麼其他由惡意攻擊者注入的腳本,就會被認定成不該執行的,就不會被執行。

  3. Stored、Reflected 防範。這兩種都必須由後端進行防範,任何允許用戶輸入的內容都要檢查,刪除相關的關鍵字,像是 <script>onerror 等指令。


相關文章

🧵 如果你想收到最即時的內容更新,可以在 FacebookInstagram 上追蹤我們