防止 CSRF、XSSI 和跨來源資訊外洩。
為什麼 Google 要重視隔離網路資源?
許多網頁應用程式容易遭受跨來源攻擊,例如跨網站要求偽造 (CSRF)、跨網站指令碼納入 (XSSI)、時間攻擊、跨來源資訊外洩或推測執行側邊攻擊 (Spectre) 攻擊。
擷取中繼資料要求標頭可讓您部署強大的縱深防禦機制 (資源隔離政策),以保護應用程式免受這些常見的跨來源攻擊。
由指定網頁應用程式公開的資源通常只會由應用程式本身載入,而不會由其他網站載入。在這種情況下,要根據擷取中繼資料要求標頭部署資源隔離政策並不容易,同時還可保護應用程式免受跨網站攻擊。
瀏覽器相容性
目前所有新版瀏覽器引擎都支援擷取中繼資料要求標頭。
背景
網路為預設開放,而您的應用程式伺服器無法輕易保護自身不受外部應用程式的通訊所影響,所以許多跨網站攻擊都可能成為這項攻擊目標。 典型的跨來源攻擊是跨網站請求偽造 (CSRF) 攻擊,攻擊者會先將使用者導向自己所控制的網站,然後將表單提交至使用者登入的伺服器。由於伺服器無法辨別請求是否源自另一個網域 (跨網站),而且瀏覽器會自動將 Cookie 附加至跨網站的要求,因此伺服器會代表使用者執行攻擊者要求的動作。
其他跨網站攻擊 (如跨網站指令碼納入 (XSSI) 或跨來源資訊外洩) 的本質與 CSRF 類似,且依賴在攻擊者控制的文件中載入受害應用程式的資源,並洩露受害應用程式的相關資訊。由於應用程式無法輕易區分可信任要求和不受信任的要求,因此無法捨棄惡意的跨網站流量流量。
隆重推出擷取中繼資料
擷取中繼資料要求標頭是全新的網路平台安全性功能,旨在協助伺服器防範跨來源攻擊。透過在一組 Sec-Fetch-*
標頭中提供 HTTP 要求的結構定義相關資訊,可讓回應伺服器在處理要求之前套用安全性政策。這讓開發人員能夠根據要求的方式和用途,決定是否接受或拒絕要求,從而能夠只回應自家應用程式提出的合法要求。
Sec-Fetch-Site
Sec-Fetch-Site
會告知伺服器傳送要求的是哪個網站。瀏覽器會將這個值設為下列其中一項:
same-origin
(如果要求是由您的應用程式發出,例如site.example
)same-site
(如果要求是由網站的子網域 (例如bar.site.example
) 提出)none
:如果要求是由使用者與使用者代理程式互動 (例如點按書籤) 明確導致cross-site
:如果要求是由其他網站 (例如evil.example
) 傳送
Sec-Fetch-Mode
Sec-Fetch-Mode
表示要求的「模式」。這大致對應至要求的類型,並可讓您區分資源負載與導覽要求。舉例來說,目的地 navigate
表示頂層導覽要求,no-cors
則代表載入圖片等資源要求。
Sec-Fetch-Dest
Sec-Fetch-Dest
會公開要求的目的地 (例如 script
或 img
標記造成瀏覽器要求資源)。
如何使用擷取中繼資料來防範跨來源攻擊
這些要求標頭提供的額外資訊雖然簡單,但額外的內容可讓您在伺服器端建立強大的安全性邏輯,而且只需使用幾行程式碼即可 (也稱為資源隔離政策)。
實施資源隔離政策
資源隔離政策會禁止外部網站要求你的資源。封鎖這類流量可減少常見的跨網站漏洞,例如 CSRF、XSSI、時間攻擊和跨來源資訊外洩。您可以為應用程式的所有端點啟用這項政策,允許來自您應用程式的所有資源要求和直接導覽 (透過 HTTP GET
要求)。如果端點應在跨網站環境中載入 (例如使用 CORS 載入的端點),可選擇不採用這個邏輯。
步驟 1:允許不會傳送擷取中繼資料的瀏覽器要求
並非所有瀏覽器都支援擷取中繼資料,因此您必須檢查是否存在 sec-fetch-site
,以允許沒有設定 Sec-Fetch-*
標頭的要求。
if not req['sec-fetch-site']:
return True # Allow this request
步驟 2:允許相同網站和瀏覽器發起的要求
系統會允許任何並非源自跨來源環境 (例如 evil.example
) 的要求。具體來說,這些要求必須符合下列條件:
- 來自您自己的應用程式 (例如一律允許
site.example
要求site.example/foo.json
的相同來源要求)。 - 來自您的子網域。
- 明確是因使用者與使用者代理程式的互動 (例如直接導覽或點選書籤等) 所致。
if req['sec-fetch-site'] in ('same-origin', 'same-site', 'none'):
return True # Allow this request
步驟 3:允許簡單的頂層導覽和 iframing
為確保您的網站仍可從其他網站建立連結,請允許簡易的頂層導覽 (HTTP GET
)。
if req['sec-fetch-mode'] == 'navigate' and req.method == 'GET'
# <object> and <embed> send navigation requests, which we disallow.
and req['sec-fetch-dest'] not in ('object', 'embed'):
return True # Allow this request
步驟 4:停用用來提供跨網站流量的端點 (選用)
在某些情況下,您的應用程式可能會提供需要跨網站載入的資源。這些資源必須在個別路徑或每個端點上豁免。這類端點的範例如下:
- 端點需用於跨來源存取:如果應用程式提供的端點已啟用
CORS
,請明確停用端點與資源隔離功能,以確保仍可向這些端點傳送跨網站要求。 - 公開資源 (例如圖片、樣式等):任何應可從其他網站載入的公開和未經驗證的資源,同樣適用於豁免情況。
if req.path in ('/my_CORS_endpoint', '/favicon.png'):
return True
步驟 5:拒絕所有其他跨網站和非導覽性質的要求
本資源隔離政策會拒絕任何其他跨網站要求,為您的應用程式防範常見的跨網站攻擊。
範例:以下程式碼示範在伺服器上完整實作完善的資源隔離政策,或以中介軟體的形式實作,拒絕潛在的惡意跨網站資源要求,同時允許簡單的瀏覽要求:
# Reject cross-origin requests to protect from CSRF, XSSI, and other bugs
def allow_request(req):
# Allow requests from browsers which don't send Fetch Metadata
if not req['sec-fetch-site']:
return True
# Allow same-site and browser-initiated requests
if req['sec-fetch-site'] in ('same-origin', 'same-site', 'none'):
return True
# Allow simple top-level navigations except <object> and <embed>
if req['sec-fetch-mode'] == 'navigate' and req.method == 'GET'
and req['sec-fetch-dest'] not in ('object', 'embed'):
return True
# [OPTIONAL] Exempt paths/endpoints meant to be served cross-origin.
if req.path in ('/my_CORS_endpoint', '/favicon.png'):
return True
# Reject all other requests that are cross-site and not navigational
return False
部署資源隔離政策
- 安裝如上方程式碼片段所示的模組,即可記錄並監控網站行為,並確保這些限制不會影響任何合法流量。
- 排除合法的跨來源端點,藉此修正可能的違規行為。
- 捨棄不符合規定的要求,強制執行政策。
找出並修正政策違規問題
建議您在伺服器端程式碼中先在報表模式中啟用政策,這樣測試政策就沒有任何效果。或者,您也可以在中介軟體中實作此邏輯,或是在反向 Proxy 中實作,記錄在實際工作環境流量套用政策時可能產生的任何違規行為。
從我們在 Google 實施「擷取中繼資料資源隔離政策」的經驗中,大部分的應用程式預設都與此類政策相容,而且很少要求豁免端點來允許跨網站流量。
強制執行資源隔離政策
確認政策不會影響到合法的正式環境流量後,即可強制執行限制,確保其他網站無法要求您的資源,保護使用者免於跨網站攻擊。