重要的 HTTP 安全標頭:CSP、HSTS、X-Content-Type-Options、X-Frame-Options 和 Referrer-Policy 詳解
HTTP 回應標頭為何對安全性至關重要
每個 HTTP 回應都帶有標頭——在主體之前發送的中繼資料行,控制瀏覽器如何處理內容。大多數標頭很平常(Content-Type、Cache-Control),但一組特定的安全性標頭會指示瀏覽器執行限制,從而封鎖整個攻擊類別。這些不是理論上的強化措施;它們是針對反覆出現在 OWASP Top 10 和 CVE 資料庫中的攻擊類別的實際防禦。設定它們對效能幾乎沒有影響——每個回應大約增加 200–400 位元組——而 securityheaders.com 等工具會對任何公開 URL 進行評分,讓你立即看到缺少哪些標頭。
關鍵洞察是安全性標頭由瀏覽器而非伺服器執行。伺服器宣布政策;瀏覽器執行它。這意味著高流量網站上的標頭配置錯誤會同時影響每位訪客的瀏覽器。反之,添加正確的標頭可以在單次部署中修正多年積累的風險。此處介紹的五個標頭——CSP、HSTS、X-Content-Type-Options、X-Frame-Options 和 Referrer-Policy——每個都針對攻擊者可能利用的不同瀏覽器行為。
Content-Security-Policy:XSS 防火牆
跨站腳本攻擊(XSS)是 OWASP Top 10 中最常見的 Web 漏洞。能夠在你的 HTML 中注入 <script> 標籤的攻擊者可以竊取會話 Cookie、重新導向使用者或竊取表單資料。Content-Security-Policy(CSP)是一種基於白名單的標頭,告訴瀏覽器哪些來源對腳本、樣式、圖片、字型和其他資源類型是可信任的。指令 Content-Security-Policy: default-src 'self' 只允許來自相同來源的資源,封鎖所有外部腳本和內聯 <script> 區塊。script-src 指令專門為 JavaScript 覆蓋預設值。
最大的 CSP 陷阱是 unsafe-inline 關鍵字。添加 script-src 'unsafe-inline' 會重新啟用內聯腳本,完全破壞 CSP 對 XSS 的保護,但這卻是網站啟用 CSP 後出現問題時最常求助的解決方法。正確的替代方案是 nonce:每次頁面載入生成一個加密隨機值,以 script-src 'nonce-r4nd0m' 包含在標頭中,並以 nonce="r4nd0m" 包含在每個合法的 <script> 標籤上。沒有匹配 nonce 的注入腳本即使內聯出現也會被封鎖。對於尚未準備好嚴格政策的團隊,Content-Security-Policy-Report-Only 會將違規報告發送到收集端點而不封鎖任何內容——這是在執行政策之前衡量其影響的安全方式。
HTTP Strict Transport Security:防止 HTTPS 降級攻擊
SSL 剝離是 2009 年 Black Hat 大會上公開演示的降級攻擊。路徑上的主動攻擊者攔截使用者的初始 HTTP 請求(在任何重新導向到 HTTPS 之前),並將其作為純 HTTP 代理到來源,同時向使用者提供加密連線。使用者在某些瀏覽器中看到掛鎖,但攻擊者與伺服器之間的連線是未加密的——憑證和會話 Cookie 以明文可見。HTTP Strict Transport Security(HSTS)通過指示瀏覽器完全拒絕域名的 HTTP 連線來關閉此漏洞,期間由 max-age 指令以秒為單位定義。
典型的強 HSTS 標頭是 Strict-Transport-Security: max-age=31536000; includeSubDomains; preload。31536000 秒的 max-age 是一年——納入 HSTS 預載清單所需的最低要求。includeSubDomains 將政策擴展到每個子域名。preload 表示有意加入 hstspreload.org 上的瀏覽器內建預載清單;一旦列入該清單,即使在首次訪問網站並收到標頭之前,瀏覽器也會拒絕 HTTP 連線。關鍵限制:HSTS 必須通過有效的 HTTPS 回應傳遞。通過 HTTP 發送的標頭將被忽略。部署 includeSubDomains 前先進行測試——如果任何子域名缺少有效的 TLS 憑證,使用者在整個 max-age 期間將被鎖定無法訪問。
X-Content-Type-Options 和 X-Frame-Options:兩個單值即可的安全提升
MIME 嗅探是一種遺留行為,某些瀏覽器會檢查回應的前幾個位元組來猜測其內容類型,覆蓋 Content-Type 標頭。Internet Explorer 是最積極的 MIME 嗅探器;如果前幾個位元組看起來像標記語言,它會將 .jpg 作為 HTML 執行。能夠向你的網站上傳內容(圖片、日誌文件)的攻擊者可以製作在瀏覽器嗅探時被作為腳本執行的有效載荷。X-Content-Type-Options: nosniff 指示所有現代瀏覽器信任宣告的 Content-Type 並完全跳過嗅探。它只有一個有效值——nosniff——沒有理由不在每個回應上設定它。
點擊劫持將你的網站嵌入攻擊者控制頁面上的 <iframe> 中,然後覆蓋透明按鈕,使使用者在不知情的情況下點擊你網站上的 UI 元素。X-Frame-Options: DENY 阻止任何人框架你的頁面;X-Frame-Options: SAMEORIGIN 只允許來自相同來源的頁面框架。ALLOW-FROM uri 變體已過時,目前瀏覽器不支援。現代等效項是 CSP frame-ancestors 指令(frame-ancestors 'none' 對應 DENY,frame-ancestors 'self' 對應 SAMEORIGIN),它還支援多個允許的來源。由於不是所有瀏覽器在所有情境下都檢查 frame-ancestors,同時設定 X-Frame-Options 和 frame-ancestors CSP 指令可提供縱深防禦。
Referrer-Policy:通過 Referer 標頭控制資訊洩漏
HTTP Referer 標頭(由於 RFC 中的歷史拼字錯誤,只有一個「r」)將使用者導航來源頁面的完整 URL 發送到該頁面載入的每個外部資源——圖片、腳本、樣式表以及連結點擊的目標。如果已登入的使用者訪問 /account/reset?token=eyJ...,而該頁面載入了第三方分析腳本,則該腳本的請求在 Referer 標頭中攜帶完整 URL,包括重設令牌。通過 referrer 洩漏令牌是有據可查的漏洞類別;GitHub 在 2020 年修補了一個基於 referrer 的令牌暴露問題。
Referrer-Policy 標頭取代了早期的 Meta referrer 機制和 Referer 標頭抑制解決方法。政策 strict-origin-when-cross-origin 是推薦的預設值:對於同源請求發送完整 URL(對內部分析有用),但對於跨源請求只發送裸露的來源(https://example.com),從 HTTPS 導航到 HTTP 時不發送任何內容。no-referrer 完全不發送任何內容,最大化隱私但會破壞依賴 referrer 的分析。unsafe-url 始終發送完整 URL,包括路徑和查詢字串——2020 年之前的瀏覽器預設值,也是大多數歷史 referrer 洩漏的來源。Chrome、Firefox 和 Safari 都在 2020–2021 年將 strict-origin-when-cross-origin 作為沒有政策標頭時的預設值,但明確設定它可確保跨所有瀏覽器版本的一致行為。
任何網站的實用安全標頭基準
對於靜態網站或簡單的 Web 應用程式,四個標頭以最小的配置複雜性覆蓋最常見的攻擊向量:X-Content-Type-Options: nosniff(始終,一行);X-Frame-Options: SAMEORIGIN(除非你的網站需要合法地被嵌入);Referrer-Policy: strict-origin-when-cross-origin;以及 Strict-Transport-Security: max-age=31536000; includeSubDomains(一旦確認每個子域名都是 HTTPS)。CSP 需要更多規劃——從 Content-Security-Policy-Report-Only 和報告端點開始,收集幾天的違規報告,然後編寫只允許你實際使用的政策。
標頭配置位置取決於你的技術棧:Nginx 在伺服器區塊中使用 add_header 指令;Apache 在 httpd.conf 或 .htaccess 中使用 Header always set;Vercel、Netlify 和 Cloudflare Pages 各有標頭配置文件或儀表板設定。大多數 CDN 允許在邊緣注入標頭,這比應用程式層級標頭更好,因為即使對於快取回應,CDN 也能傳遞它們。TeaFun HTTP 標頭檢查工具可獲取任何公開 URL 並顯示存在哪些安全性標頭、其值以及每個標頭功能的快速參考說明——在部署標頭更改之前和之後使用它來審核網站。