HSTS(HTTP Strict Transport Security)是一個安全響應頭,告訴瀏覽器始終透過 HTTPS 連線——即使使用者輸入 http:// 或點選 HTTP 連結。瀏覽器一旦收到 HSTS 頭,就會自動將該域名的所有未來請求升級為 HTTPS,防止降級攻擊和不安全連線。
為什麼 HSTS 很重要
沒有 HSTS 時,對你站點的首次請求可能是 HTTP(在 301 重新導向生效之前)。在這個短暫視窗內,網路上的攻擊者可以:
- 剝離 HTTPS —— 攔截重新導向並讓使用者停留在 HTTP(SSL 剝離攻擊)
- 竊取 Cookie —— 如果 Cookie 在初始 HTTP 請求中傳送
- 注入內容 —— 修改重新導向響應
HSTS 消除了這個視窗。首次 HTTPS 訪問後,瀏覽器不再嘗試 HTTP。
如何啟用 HSTS
Nginx
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always;
將此新增到 HTTPS server 塊(埠 443)中,不是 HTTP 重新導向塊。
Apache
Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains"
需要 mod_headers(sudo a2enmod headers)。
Cloudflare
Dashboard → SSL/TLS → Edge Certificates → HTTP Strict Transport Security (HSTS) → Enable。
HSTS 引數
| 引數 | 示例 | 含義 |
|---|---|---|
max-age | 63072000(2 年) | 瀏覽器記住使用 HTTPS 的時長(秒) |
includeSubDomains | — | 將 HSTS 同時應用於所有子域名 |
preload | — | 表明意圖加入 HSTS 預載入列表 |
選擇 max-age
| 階段 | max-age | 目的 |
|---|---|---|
| 測試 | 300(5 分鐘) | 在承諾之前驗證 HTTPS 正常工作 |
| 確認 | 604800(1 周) | 如需回滾風險較低 |
| 生產 | 31536000(1 年) | 標準推薦 |
| 長期 | 63072000(2 年) | 預載入列表要求 |
從小值開始,逐步增加。 如果 HTTPS 在長 max-age 快取期間出現故障,訪問者將完全無法訪問你的網站——瀏覽器拒絕透過 HTTP 連線。
HSTS 預載入
HSTS 預載入列表是硬編碼在瀏覽器中的域名列表,始終使用 HTTPS,即使是第一次訪問(在收到任何 HSTS 頭之前)。
預載入的要求
- 提供有效的 HTTPS 證書
- 在同一主機上將 HTTP 重新導向到 HTTPS
- HSTS 頭的
max-age≥ 63072000(2 年) - 包含
includeSubDomains指令 - 包含
preload指令
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
提交預載入
前往 hstspreload.org,輸入你的域名並提交。稽核後(數週到數月),你的域名將被新增到瀏覽器內建列表中。
預載入的注意事項
- 很難撤銷。 從預載入列表移除需要數月時間,並需要瀏覽器釋出一個新版本。在此期間,你的域名只能透過 HTTPS 訪問。
includeSubDomains是強制的 —— 所有子域名都必須支援 HTTPS。如果staging.example.com沒有證書,它將變得不可訪問。- 只有當你確信所有當前和未來的子域名都支援 HTTPS 時才進行預載入。
常見錯誤
在 HTTP 響應中設定 HSTS
HSTS 必須僅在 HTTPS 上傳送。如果你的 HTTP 重新導向也傳送了 HSTS 頭,瀏覽器會忽略它(規範要求 HTTPS)。只在埠 443 的塊中設定該頭。
忘記子域名
includeSubDomains 將 HSTS 應用於所有子域名。如果 internal.example.com 沒有 HTTPS,它將變得不可達。啟用前審計所有子域名。
過早設定過高的 max-age
如果 HTTPS 出故障(證書過期、配置錯誤),訪問者無法回退到 HTTP。瀏覽器拒絕連線。先設 5 分鐘,驗證一切正常,然後再增加到 1 年。
如何檢查 HSTS 是否生效
curl -sI https://yourdomain.com | grep -i strict-transport
# Expected: strict-transport-security: max-age=63072000; includeSubDomains
在 Chrome DevTools 中:Network 標籤 → 點選請求 → Headers → 查詢 Strict-Transport-Security。
常見問題
HSTS 能替代 HTTP→HTTPS 重新導向嗎?
不能。HSTS 和重新導向服務於不同目的。重新導向捕獲首次 HTTP 請求。HSTS 告訴瀏覽器以後不再發起 HTTP 請求(在首次 HTTPS 訪問之後)。兩者都需要。
HSTS 會導致問題嗎?
會,如果 HTTPS 出故障的話。使用長 max-age 時,瀏覽器拒絕將 HTTP 作為回退。這就是為什麼應該從短 max-age 開始,只有在 HTTPS 穩定後才增加。
如果我在 Cloudflare 上還需要 HSTS 嗎?
Cloudflare 處理訪客→Cloudflare 的連線,但在源站啟用 HSTS 保護完整鏈路。透過 Cloudflare 面板為邊緣啟用 HSTS,如果使用 Full (Strict) 模式,也在源站啟用。
HSTS 和 upgrade-insecure-requests CSP 指令有什麼區別?
upgrade-insecure-requests 告訴瀏覽器透過 HTTPS 而非 HTTP 載入子資源(圖片、指令碼)——修復混合內容。HSTS 告訴瀏覽器始終對整個域名使用 HTTPS。它們解決不同問題,可以同時使用。