# 前端安全性

前端能夠顧慮到最直接的安全性問題大概就是 XSS 了,像是早期的留言板幾乎都沒有擋 HTML 或 JavaScript 語法,等於直接開啟了隱私大門,駭客可以直接從使用者的瀏覽器中拿取任何想要的資料送到其他網站。

你或許會想解決的方法很簡單,使用者的輸入就一律過濾 HTML 就好了呀,但問題就在於,沒有人可以保證這件事情。

這也是為什麼各大服務都曾經有 XSS 案例的產生,就算前端有意識地作好 XSS 的防護,還是沒有辦法 100% 防止 XSS 攻擊。或者更廣義地說,沒有任何一個服務(伺服器)是 100% 安全的。

不過,雖然沒辦法防止 XSS,但該做的還是要做好,至少明顯的 XSS 漏洞不要大喇喇的給別人知道。XSS 可能會發生的來源於:

  • <input /><textarea/>:送到後端的內容,記得過濾掉 HTML tag。
  • 檔案名稱、內容:例如檔案名稱叫做 <script>alert('hello')</script>,如果沒有做跳脫就直接在前端顯示的話可能會被 XSS
  • URL
  • localStorage
  • Cookie
  • 其他

除了一般的 input tag 之外,很多人忽略了像是上述的其他事項,導致駭客有機可趁。

既然我們沒辦法做到 100% 伺服器安全與 100% 防止 XSS,那麼到底該怎麼做才好呢?

其實現在有很多防護措施,都是在伺服器一部分被侵入的情況下做假設的。

你或許聽過如果實作使用者登入,資料庫都應該使用 hash 的方式來存放密碼,而非直接儲存明碼。

這是因為如果駭客入侵資料庫,能夠知道的就只有被 hash + salt 過後的密碼,無法得知使用者原始密碼,進一步防止駭客竊取。雖然資料庫被入侵本身是個很嚴重的問題,但至少還有一層保護。

cookie 如果在沒有將 httpOnly 設置為 enable 的情況下,可以透過 document.cookie

# 模板語言

另外,在使用像是 ejspug 之類的模板引擎時,也要小心渲染資料時是否有正確跳脫 HTML。通常這類型的模板引擎都會提供一個可以直接 raw HTML 的選項或語法,讓你必要時可以動態渲染 HTML,這時候就要特別小心拿到的資料是否會有造成 XSS 的可能性了。

# 後記 — Fetch Metadata Request Headers (opens new window)

這是目前正在 w3c 草案的規格,主要規範了 request 在送出時,瀏覽器會自動加入一些 request header 幫助 server 端判斷是否為正確請求。主要的 Header 有下列幾種:

# 1. Sec-Fetch-Dest

代表這個請求的目的地是哪裡。

可能的值有 audio、document、font、image、object、serviceworker 等等 (opens new window)。這樣有幾個好處,有了這些 header 的判斷,伺服器馬上就可以知道這個請求來源是否合法,例如如果這個來源是從 <img> 來的,卻不是跟伺服器要圖片,那麼十之八九是駭客,我們就可以直接回應錯誤給他。

# 2. Sec-Fetch-Mode

代表請求的模式。主要有 cors、navigate、nested-navigate、no-cors 等等,來判斷這個請求的模式是什麼,類似 fetch 當中的 mode。

像是 Set-Fetch-User 我們也可以知道使用者是否是透過操作(例如點擊、鍵盤等等)來發出請求的。

# 3. Sec-Fetch-Site

代表請求的來源是同源還是跨域。

# 4. Sec-Fetch-User

這個標頭的值是布林值,只有在請求是只有在 navigation request (opens new window)(request 的目的地為 document)而且有互動時(例如按下按鈕、鍵盤等等)才會是 true,伺服器可以根據這個標頭來判斷使用者觸發請求的方式是否合法。

像是點擊 form 表單送出的時候,因為是由 document 送出請求,且使用者有互動(點擊按鈕送出),所以 Set-Fetch-User 會是 ?T

有了這些標頭之後,server 端可以更容易判定這個請求是否來自於正確的地方,例如明明應該是要用 fetch 送過來的請求卻是從 img tag 送出,那麼就可以直接拒絕這個請求。