半熟前端

軟體工程師 / 台灣人 / 在前端的路上一邊探索其他領域的可能性

前端

更安全的請求標頭 - Fetch Metadata Request Headers

有一天在開發頁面的時候,為了要檢查請求 Header 的欄位是否正確,打開開發工具一看,發現了請求多出了幾個可疑的 header:

network

有注意到可疑的地方嗎?仔細一看發現,怎麼有三個以 Sec-Fetch-* 開頭的標頭。 這引起了我的注意,我並沒有設定這些標頭,也沒有套用其他函式,為什麼會自己幫我加上這些標頭,猜測應該是瀏覽器在作祟。

查了一下 google 發現,原來這是一個新的草案,叫做 Fetch Metadata Request Headers。目前只有 chrome 才會加上這些標頭,Firefox, Safari 並不會。

再談同源政策(CORS)

我們都知道,瀏覽器為了防止一些有心人士用奇怪的手法竊取你的資料,限制了某些來源的存取條件,例如跨域請求時需要加上 Access-Control-Allow-Origin 或是 Preflight 請求等等,詳細的內容可以參考我之前寫的「如何和 CORS 與 Cookie 打交道」。

儘管如此還是有些缺陷,像是 <img/> 仍然可以送出跨域請求,這樣有心人士就可以略過 CORS 的限制。當然,如果伺服器有做好基本的防護措施,還是可以擋下大部分不安全的請求。

如果可以再送出請求的時候,加上一些額外的標頭資訊(metadata)描述這個請求是從哪裡來的話,伺服器也可以根據標頭來做適當的回應,於是誕生出這樣的草案。

標頭規格:

目前主要有四個標頭在草案當中:

1. Sec-Fetch-Dest

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

可能的值有 audio、document、font、image、object、serviceworker 等等。這樣有幾個好處,有了這些 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(request 的目的地為 document)而且有互動時(例如按下按鈕、鍵盤等等)才會是 true,伺服器可以根據這個標頭來判斷使用者觸發請求的方式是否合法。

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

有辦法把標頭拿掉嗎?

如果成為規範之一的話,可能沒有辦法把它拿掉。另外你不可以透過手動設定來改寫標頭的值,因為它屬於 forbidden headers 之一。

結論

以往要做到類似的事情,都會用自定義的 header 來防範,但還是有可能被偽造,而且加上自定義的標頭就需要做 prelight 的檢查,又多了一份工。從規範下手的好處在於這些標頭沒辦法被輕易改寫,而且提供了統一的標準,有了這些標頭,就可以讓後端在收到請求時多做一些判斷,進而提高安全性。