HSTS(HTTP Strict Transport Security)是一種網頁安全機制,透過 HTTP 回應標頭強制瀏覽器僅使用 HTTPS 連線存取網站。本文將詳細介紹 HSTS 的運作原理、設定方式,以及如何將網站加入 HSTS Preload List。
HSTS 概述
什麼是 HSTS?
HSTS 全名為 HTTP Strict Transport Security(HTTP 嚴格傳輸安全),是一種網頁安全政策機制。當網站啟用 HSTS 後,瀏覽器會記住該網站必須使用 HTTPS 連線,並在指定時間內自動將所有 HTTP 請求轉換為 HTTPS。
HSTS 運作流程
- 使用者首次透過 HTTPS 存取網站
- 伺服器回應時在標頭中包含
Strict-Transport-Security - 瀏覽器記錄此網站的 HSTS 政策
- 在有效期內,瀏覽器自動將 HTTP 請求轉為 HTTPS
- 若憑證無效,瀏覽器會阻止連線並顯示錯誤
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 是一種中間人攻擊方式:
- 攻擊者攔截使用者與伺服器之間的流量
- 將使用者的 HTTP 請求轉發至伺服器的 HTTPS
- 伺服器以 HTTPS 回應攻擊者
- 攻擊者以 HTTP 將內容傳給使用者
- 使用者看到的是未加密的 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
- 子網域使用不同的憑證管理
設定範例
1
| Strict-Transport-Security: max-age=31536000; includeSubDomains
|
注意事項
啟用前請確認:
- 所有子網域都已設定有效的 SSL 憑證
- 沒有僅支援 HTTP 的子網域
- 內部系統或測試環境不會受到影響
preload 參數
參數說明
preload 表示網站所有者希望將網站加入瀏覽器內建的 HSTS Preload List。加入後,瀏覽器在首次連線時就會使用 HTTPS。
Preload 的優點
- 消除首次連線的安全漏洞
- 無需等待使用者首次訪問
- 提供最高等級的 HTTPS 保護
設定範例
1
| Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
|
申請條件
要加入 HSTS Preload List,網站必須符合以下條件:
- 擁有有效的 SSL 憑證
- 將所有 HTTP 流量重新導向至 HTTPS
- 所有子網域都支援 HTTPS
- 在基礎網域設定 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 設定
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
- 確認網站符合所有條件
- 前往 hstspreload.org
- 輸入網域名稱進行檢查
- 確認無誤後提交申請
- 等待審核與瀏覽器更新
從 Preload List 移除
如果需要從 Preload List 移除網站:
- 前往 hstspreload.org/removal
- 填寫移除申請表單
- 等待審核(可能需要數月時間)
注意: 移除過程非常緩慢,因為需要等待所有瀏覽器更新。請在提交前謹慎評估。
常見檢查錯誤
| 錯誤 | 解決方案 |
|---|
| 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
|
使用線上工具
瀏覽器開發者工具
- 開啟瀏覽器開發者工具(F12)
- 切換至「Network」分頁
- 重新整理頁面
- 點選第一個請求
- 在「Headers」中查看 Response Headers
注意事項與最佳實踐
部署建議
- 漸進式部署:從較短的 max-age 開始,逐步增加
- 先測試再正式:確保所有服務都支援 HTTPS
- 監控錯誤:注意使用者回報的連線問題
- 備份計畫:了解如何在緊急情況下處理
常見錯誤
| 錯誤 | 影響 | 預防方式 |
|---|
| 子網域未設定 HTTPS | 使用者無法存取子網域 | 確認所有子網域都有有效憑證 |
| max-age 設定過長 | 問題發生時難以快速修復 | 初期使用較短的數值 |
| 內部服務受影響 | 內部系統無法使用 HTTP | 將內部服務排除或設定憑證 |
| 憑證過期 | 使用者完全無法存取網站 | 設定自動續約與監控 |
安全考量
- HSTS 無法防護首次訪問(除非使用 Preload)
- 憑證過期會導致網站完全無法存取
- 設定錯誤可能造成長時間的服務中斷
參考資料