HSTS HTTP 嚴格傳輸安全設定

HSTS HTTP Strict Transport Security Configuration

HSTS(HTTP Strict Transport Security)是一種網頁安全機制,透過 HTTP 回應標頭強制瀏覽器僅使用 HTTPS 連線存取網站。本文將詳細介紹 HSTS 的運作原理、設定方式,以及如何將網站加入 HSTS Preload List。

HSTS 概述

什麼是 HSTS?

HSTS 全名為 HTTP Strict Transport Security(HTTP 嚴格傳輸安全),是一種網頁安全政策機制。當網站啟用 HSTS 後,瀏覽器會記住該網站必須使用 HTTPS 連線,並在指定時間內自動將所有 HTTP 請求轉換為 HTTPS。

HSTS 運作流程

  1. 使用者首次透過 HTTPS 存取網站
  2. 伺服器回應時在標頭中包含 Strict-Transport-Security
  3. 瀏覽器記錄此網站的 HSTS 政策
  4. 在有效期內,瀏覽器自動將 HTTP 請求轉為 HTTPS
  5. 若憑證無效,瀏覽器會阻止連線並顯示錯誤

HSTS 的優點

優點說明
防止協議降級攻擊阻止攻擊者將 HTTPS 連線降級為 HTTP
防止中間人攻擊減少 SSL Stripping 攻擊的風險
提升安全性確保所有通訊都經過加密
使用者體驗減少重新導向次數,加快頁面載入

為什麼需要 HSTS

HTTP 重新導向的安全風險

傳統的 HTTP 到 HTTPS 重新導向存在安全漏洞:

1
2
3
4
5
使用者輸入 http://example.com
伺服器回應 301 Redirect to https://example.com
攻擊者可在此過程中攔截並修改流量

SSL Stripping 攻擊

SSL Stripping 是一種中間人攻擊方式:

  1. 攻擊者攔截使用者與伺服器之間的流量
  2. 將使用者的 HTTP 請求轉發至伺服器的 HTTPS
  3. 伺服器以 HTTPS 回應攻擊者
  4. 攻擊者以 HTTP 將內容傳給使用者
  5. 使用者看到的是未加密的 HTTP 頁面

HSTS 如何防護

啟用 HSTS 後,瀏覽器會:

  • 自動將所有 HTTP 請求轉換為 HTTPS(不經過伺服器重新導向)
  • 在憑證錯誤時阻止使用者繼續瀏覽
  • 在快取有效期內持續執行此政策

HSTS 標頭語法

基本格式

1
Strict-Transport-Security: max-age=<seconds>; includeSubDomains; preload

完整範例

1
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload

參數說明

參數必要性說明
max-age必要HSTS 政策的有效時間(秒)
includeSubDomains選用將政策套用至所有子網域
preload選用表示網站要求加入 HSTS Preload List

max-age 參數

參數說明

max-age 指定瀏覽器應記住此網站必須使用 HTTPS 的時間長度,以秒為單位。

建議數值

階段建議值說明
測試階段300(5 分鐘)確保設定正確,避免長時間鎖定
初期部署86400(1 天)確認無問題後逐步增加
穩定運行31536000(1 年)建議的最終數值
Preload 要求31536000(1 年)申請 Preload 的最低要求

設定範例

測試階段:

1
Strict-Transport-Security: max-age=300

正式環境:

1
Strict-Transport-Security: max-age=31536000

includeSubDomains 參數

參數說明

includeSubDomains 指示瀏覽器將 HSTS 政策套用至網站的所有子網域。

使用時機

適合使用的情況:

  • 所有子網域都支援 HTTPS
  • 需要保護整個網域架構

不適合使用的情況:

  • 部分子網域尚未支援 HTTPS
  • 子網域使用不同的憑證管理

設定範例

1
Strict-Transport-Security: max-age=31536000; includeSubDomains

注意事項

啟用前請確認:

  1. 所有子網域都已設定有效的 SSL 憑證
  2. 沒有僅支援 HTTP 的子網域
  3. 內部系統或測試環境不會受到影響

preload 參數

參數說明

preload 表示網站所有者希望將網站加入瀏覽器內建的 HSTS Preload List。加入後,瀏覽器在首次連線時就會使用 HTTPS。

Preload 的優點

  • 消除首次連線的安全漏洞
  • 無需等待使用者首次訪問
  • 提供最高等級的 HTTPS 保護

設定範例

1
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload

申請條件

要加入 HSTS Preload List,網站必須符合以下條件:

  1. 擁有有效的 SSL 憑證
  2. 將所有 HTTP 流量重新導向至 HTTPS
  3. 所有子網域都支援 HTTPS
  4. 在基礎網域設定 HSTS 標頭,包含:
    • max-age 至少為 31536000(1 年)
    • 必須包含 includeSubDomains
    • 必須包含 preload

Nginx 設定

基本設定

在 Nginx 設定檔中加入 HSTS 標頭:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
server {
    listen 443 ssl http2;
    server_name example.com;

    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    # HSTS 設定
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;

    # 其他設定...
}

完整安全設定範例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
server {
    listen 80;
    server_name example.com www.example.com;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name example.com www.example.com;

    # SSL 憑證
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    # SSL 協議設定
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
    ssl_prefer_server_ciphers off;

    # HSTS
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;

    # 其他安全標頭
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-XSS-Protection "1; mode=block" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;

    root /var/www/example.com/html;
    index index.html index.htm;

    location / {
        try_files $uri $uri/ =404;
    }
}

測試設定

1
2
3
4
5
# 測試 Nginx 設定語法
sudo nginx -t

# 重新載入設定
sudo systemctl reload nginx

驗證 HSTS 標頭

1
curl -I https://example.com

預期輸出應包含:

1
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload

Apache 設定

啟用 Headers 模組

1
2
sudo a2enmod headers
sudo systemctl restart apache2

基本設定

在虛擬主機設定中加入:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<VirtualHost *:443>
    ServerName example.com

    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem

    # HSTS 設定
    Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"

    DocumentRoot /var/www/example.com/html
</VirtualHost>

完整安全設定範例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<VirtualHost *:80>
    ServerName example.com
    ServerAlias www.example.com
    Redirect permanent / https://example.com/
</VirtualHost>

<VirtualHost *:443>
    ServerName example.com
    ServerAlias www.example.com

    # SSL 設定
    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem

    # SSL 協議設定
    SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
    SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384
    SSLHonorCipherOrder off

    # 安全標頭
    Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
    Header always set X-Frame-Options "SAMEORIGIN"
    Header always set X-Content-Type-Options "nosniff"
    Header always set X-XSS-Protection "1; mode=block"
    Header always set Referrer-Policy "strict-origin-when-cross-origin"

    DocumentRoot /var/www/example.com/html

    <Directory /var/www/example.com/html>
        Options -Indexes +FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>
</VirtualHost>

測試設定

1
2
3
4
5
# 測試 Apache 設定語法
sudo apachectl configtest

# 重新載入設定
sudo systemctl reload apache2

HSTS Preload List

什麼是 HSTS Preload List?

HSTS Preload List 是由 Google 維護的網站清單,被內建在主流瀏覽器中。清單中的網站會被瀏覽器強制使用 HTTPS 連線,即使是首次訪問也不會使用 HTTP。

支援的瀏覽器

瀏覽器支援版本
Google Chrome所有版本
Mozilla Firefox所有版本
Microsoft Edge所有版本
Apple Safari所有版本
Opera所有版本

提交網站至 Preload List

  1. 確認網站符合所有條件
  2. 前往 hstspreload.org
  3. 輸入網域名稱進行檢查
  4. 確認無誤後提交申請
  5. 等待審核與瀏覽器更新

從 Preload List 移除

如果需要從 Preload List 移除網站:

  1. 前往 hstspreload.org/removal
  2. 填寫移除申請表單
  3. 等待審核(可能需要數月時間)

注意: 移除過程非常緩慢,因為需要等待所有瀏覽器更新。請在提交前謹慎評估。

常見檢查錯誤

錯誤解決方案
max-age 太短設定至少為 31536000(1 年)
缺少 includeSubDomains加入 includeSubDomains 參數
缺少 preload加入 preload 參數
HTTP 未重新導向設定 HTTP 301 重新導向至 HTTPS
子網域無法使用 HTTPS為所有子網域設定有效憑證

測試與驗證

使用 curl 測試

1
2
3
4
5
# 檢查 HSTS 標頭
curl -I https://example.com | grep -i strict

# 完整標頭檢查
curl -I https://example.com

使用線上工具

瀏覽器開發者工具

  1. 開啟瀏覽器開發者工具(F12)
  2. 切換至「Network」分頁
  3. 重新整理頁面
  4. 點選第一個請求
  5. 在「Headers」中查看 Response Headers

注意事項與最佳實踐

部署建議

  1. 漸進式部署:從較短的 max-age 開始,逐步增加
  2. 先測試再正式:確保所有服務都支援 HTTPS
  3. 監控錯誤:注意使用者回報的連線問題
  4. 備份計畫:了解如何在緊急情況下處理

常見錯誤

錯誤影響預防方式
子網域未設定 HTTPS使用者無法存取子網域確認所有子網域都有有效憑證
max-age 設定過長問題發生時難以快速修復初期使用較短的數值
內部服務受影響內部系統無法使用 HTTP將內部服務排除或設定憑證
憑證過期使用者完全無法存取網站設定自動續約與監控

安全考量

  • HSTS 無法防護首次訪問(除非使用 Preload)
  • 憑證過期會導致網站完全無法存取
  • 設定錯誤可能造成長時間的服務中斷

參考資料

comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy