前端能夠顧慮到最直接的安全性問題大概就是 XSS 了,像是早期的留言板幾乎都沒有擋 HTML 或 JavaScript 語法,等於直接開啟了隱私大門,駭客可以直接從使用者的瀏覽器中拿取任何想要的資料送到其他網站。
你或許會想解決的方法很簡單,使用者的輸入就一律過濾 HTML 就好了呀,但問題就在於,沒有人可以保證這件事情。
這也是為什麼各大服務都曾經有 XSS 案例的產生,就算前端有意識地作好 XSS 的防護,還是沒有辦法 100% 防止 XSS 攻擊。或者更廣義地說,沒有任何一個服務(伺服器)是 100% 安全的。
不過,雖然沒辦法防止 XSS,但該做的還是要做好,至少明顯的 XSS 漏洞不要大喇喇的給別人知道。XSS 可能會發生的來源於:
<input />
與 <textarea/>
:送到後端的內容,記得過濾掉 HTML tag。<script>alert('hello')</script>
,如果沒有做跳脫就直接在前端顯示的話可能會被 XSS除了一般的 input
tag 之外,很多人忽略了像是上述的其他事項,導致駭客有機可趁。
既然我們沒辦法做到 100% 伺服器安全與 100% 防止 XSS,那麼到底該怎麼做才好呢?
其實現在有很多防護措施,都是在伺服器一部分被侵入的情況下做假設的。
你或許聽過如果實作使用者登入,資料庫都應該使用 hash 的方式來存放密碼,而非直接儲存明碼。
這是因為如果駭客入侵資料庫,能夠知道的就只有被 hash + salt 過後的密碼,無法得知使用者原始密碼,進一步防止駭客竊取。雖然資料庫被入侵本身是個很嚴重的問題,但至少還有一層保護。
cookie 如果在沒有將 httpOnly 設置為 enable 的情況下,可以透過 document.cookie
另外,在使用像是 ejs
、pug
之類的模板引擎時,也要小心渲染資料時是否有正確跳脫 HTML。通常這類型的模板引擎都會提供一個可以直接 raw HTML 的選項或語法,讓你必要時可以動態渲染 HTML,這時候就要特別小心拿到的資料是否會有造成 XSS 的可能性了。
這是目前正在 w3c 草案的規格,主要規範了 request 在送出時,瀏覽器會自動加入一些 request header 幫助 server 端判斷是否為正確請求。主要的 Header 有下列幾種:
代表這個請求的目的地是哪裡。
可能的值有 audio、document、font、image、object、serviceworker 等等。這樣有幾個好處,有了這些 header 的判斷,伺服器馬上就可以知道這個請求來源是否合法,例如如果這個來源是從 <img>
來的,卻不是跟伺服器要圖片,那麼十之八九是駭客,我們就可以直接回應錯誤給他。
代表請求的模式。主要有 cors、navigate、nested-navigate、no-cors 等等,來判斷這個請求的模式是什麼,類似 fetch
當中的 mode。
像是 Set-Fetch-User
我們也可以知道使用者是否是透過操作(例如點擊、鍵盤等等)來發出請求的。
代表請求的來源是同源還是跨域。
這個標頭的值是布林值,只有在請求是只有在 navigation request(request 的目的地為 document)而且有互動時(例如按下按鈕、鍵盤等等)才會是 true,伺服器可以根據這個標頭來判斷使用者觸發請求的方式是否合法。
像是點擊 form 表單送出的時候,因為是由 document 送出請求,且使用者有互動(點擊按鈕送出),所以 Set-Fetch-User
會是 ?T
。
有了這些標頭之後,server 端可以更容易判定這個請求是否來自於正確的地方,例如明明應該是要用 fetch 送過來的請求卻是從 img
tag 送出,那麼就可以直接拒絕這個請求。
<input />
與<textarea/>
:送到後端的內容,記得過濾掉 HTML tag。
這是指說後端寫入之前應該要把 html tag 過濾掉嗎?滿好奇這邊指的過濾是 filter(直接拿掉)還是 escape
沒有仔細思考這個問題,不過通常我都是指 escape。
純文字就 escape,但如果是 WYSIWYG (富文本編輯器) 的內容就要過濾 HTML tag。