HTTP Strict Transport Security (HSTS) in ASP.NET Core
本文是《9012年了,還不會Https》的後篇,本文著重聊一聊 HTTP Strict Transport Security協議的概念和應用。
啟用HTTPS還不夠安全
站點通過HTTPS 對外提供服務,使用者在訪問某站點,往往會直接輸入站點域名,而不是完整的HTTPS地址,站點一般會發送301重定向,要求瀏覽器升級到HTTPS連線。
將所有非安全請求重定向到安全URL是常規做法,但是中間人仍然可以在重定向發生前劫持連線。
HSTS指示瀏覽器只能使用HTTPS訪問域名,來處理潛在的中間人劫持風險。即使使用者輸入或使用普通的HTTP連線,瀏覽器也嚴格將連線升級到HTTPS。
HSTS
HSTS是一種可選的安全增強策略,已經由IETF RFC6797中指定。
服務端通過Strict-Transport-Security
響應頭來通知客戶端應用 HSTS協議。
Strict-Transport-Security: max-age=31536000; includeSubDomains
# inclueSubDomains 是可選引數,告知瀏覽器將HSTS策略用到當前域的子域。
一旦瀏覽器認可這個響應頭,知曉訪問這個域名的所有請求必須使用HTTPS連線,將會在1年時間內快取這個約定。
當支援 HSTS的瀏覽器認可該響應頭:
- 瀏覽器為域名儲存(阻止請求使用HTTP連線)配置,瀏覽器將強制所有請求通過 HTTPS
- 瀏覽器阻止使用者使用不安全/無效證書,會顯示禁用提示(允許使用者臨時信任該證書)
因為HSTS策略由客戶端強制執行,有一些前置條件:
- 客戶端必須支援 HSTS 協議
- 必須要有一次成功的HTTPS請求,這樣才能建立HSTS 策略
Preload HSTS
細心的你可能發現,HSTS還是存在一個薄弱漏洞,那就是瀏覽器沒有當前HSTS資訊,或者第一次訪問; 或者新作業系統,瀏覽器重灌,清除瀏覽器快取;HSTS資訊的max-age過期;
依然需要一次明文HTTP請求和重定向才能升級到HTTPS並 重新整理HSTS資訊,這一次依然給攻擊者可乘之機,針對以上攻擊,HSTS的應對辦法是在瀏覽器內建一個域名列表,這個列表內域名,瀏覽器都會使用HTTPS發起連線,這個列表由Chrome維護,主流瀏覽器均在使用。
Nginx
在Nginx中設定 HSTS相對簡單:
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
# always 引數確保所有的響應都有 STS Header, 舊版本(低於1.7.5)不支援always引數。
nginx add_header 的繼承規則:
如果某個配置塊包含一個add_header 指令,那麼將不會繼承上層的headers, 因此你需要在內部配置塊重申 add_header 指令。
server { listen 443 ssl; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; # This 'location' block inherits the STS header location / { root /usr/share/nginx/html; } # Because this 'location' block contains another 'add_header' directive, # we must redeclare the STS header location /servlet { add_header X-Served-By "My Servlet Handler"; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; proxy_pass http://localhost:8080; } }
ASP.NETCore的福利時間
若使用 Kestrel 作為邊緣(face-to-internet) web伺服器, 參見下面的服務配置
- 為STS header設定了preload引數,Preload不是RFC HSTS規範的一部分,但是瀏覽器支援在全新安裝時預載入HSTS網站
- 指定子域或排除的子域 使用HSTS協議
- 設定瀏覽器快取 [訪問站點的請求均使用HTTPS協議] 這一約定的時間,預設是30天。
public void ConfigureServices(IServiceCollection services) { services.AddMvc(); services.AddHsts(options => { options.Preload = true; options.IncludeSubDomains = true; options.MaxAge = TimeSpan.FromDays(60); options.ExcludedHosts.Add("example.com"); options.ExcludedHosts.Add("www.example.com"); }); services.AddHttpsRedirection(options => { options.RedirectStatusCode = StatusCodes.Status307TemporaryRedirect; options.HttpsPort = 5001; }); }
請注意: UseHsts 對於本地回送 hosts 並不生效
- localhost: IPv4回送地址
- 127.0.0.1 IPv4回送地址
- [::1] IPv6回送地址
這也是開發者在本地啟動時 抓不到 Strict-Transport-Security 響應頭的原因。
下面給出啟用了 HSTS的 結果示例:
+ nginx 啟用HSTS: https://www.nginx.com/blog/http-strict-transport-security-hsts-and-nginx/
+ chrome清除HSTS資訊: https://www.ssl2buy.com/wiki/how-to-clear-hsts-settings-on-chrome-firefox-and-ie-browsers
&n