什麼是 XSS 攻擊?如何防範?
2023年2月9日
XSS (cross-site scripting) 是很常見的網路攻擊。身為網頁前端或後端工程師,在面試中,很常會問到 XSS 的問題,因為面試官要確定你對於 XSS 的基本概念需要有所掌握。
什麼是 XSS?
XSS 攻擊是指當某個惡意用戶,從客戶端注入攻擊腳本來達到某種目的(例如:竊取 Cookie、Session、密碼等),導致其他用戶受到波及。之所以會說是跨域 (cross-site),是因為這種攻擊方式,通常是從可信的來源發出,因此能夠繞過同源政策 (same origin policy)。舉例來說,某個用戶以合法身份進到某個網站,這時因為他是合法身份,網站認為該用戶輸入的東西是可信任的,所以當該用戶注入攻擊腳本時,網站也會認為該腳本是可信任的。
最常見的 XSS 攻擊是把 JavaScript 的腳本注入到輸入框中。例如在某個論壇網站中,惡意用戶把攻擊腳本注入到輸入框,然後變成某篇論壇貼文。這時當其他用戶進到論壇時,因為瀏覽了那篇帶有惡意腳本的貼文,所以被攻擊。
用戶可以輸入惡意的 Javascript 語法,讓系統出現問題,有興趣的可以透過這個 網站 來試試看。
因為 JavaScript 幾乎可以做到任何事,所以 XSS 的攻擊能做到的事情也是五花八門。舉例來說,竊取別的用戶的 cookie,然後透過拿到的 cookie 來發送請求;或者是竄改網頁內容。下面分享一個早些年直播平台 Twitch 因為防禦做得不夠完善,被惡搞的例子。這個例子就是透過 XSS 達成的。
XSS 攻擊的類型
Stored XSS
被保存在資料庫中的 Javascript 引起的攻擊稱為 Stored XSS,最常見的就是文章、留言等,因為用戶可以任意輸入內容,若沒有檢查,則 <script>
等標籤就會被視為正常的 HTML 做執行。
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 的方式直接顯示在前端頁面
<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?
DOM-Based 防範 - 檢查輸入欄位。此攻擊需要從前端去防範,任何的輸入欄位,例如留言欄位、檔案上傳欄位、表單的欄位等,都要有跳脫的機制,讓腳本被轉換成字符串。舉例來說,如果攻擊者輸入
<script>alert(1)</script>
,我們把<
轉成<
,在畫面上依然是呈現<
但是對程式來說,它不會被當成 HTML 標籤來解析。確保來自使用者的腳本不會被執行。透過 CSP (content security policy) 來設定有哪些網域 (domains) 來的腳本該被瀏覽器認為是該被執行的,然後瀏覽器只執行那些該被執行的腳本。舉例來說,如果設定只有來自與網站同一個網域的腳本可被執行,那麼其他由惡意攻擊者注入的腳本,就會被認定成不該執行的,就不會被執行。
Stored、Reflected 防範。這兩種都必須由後端進行防範,任何允許用戶輸入的內容都要檢查,刪除相關的關鍵字,像是
<script>
、onerror
等指令。