本文是《9012年了,還不會Https》的後篇,本文着重聊一聊 HTTP Strict Transport Security協議的概念和應用。html
站點經過HTTPS 對外提供服務,用戶在訪問某站點,每每會直接輸入站點域名,而不是完整的HTTPS地址,站點通常會發送301重定向,要求瀏覽器升級到HTTPS鏈接。nginx
將全部非安全請求重定向到安全URL是常規作法,可是中間人仍然能夠在重定向發生前劫持鏈接。web
HSTS指示瀏覽器只能使用HTTPS訪問域名,來處理潛在的中間人劫持風險。即便用戶輸入或使用普通的HTTP鏈接,瀏覽器也嚴格將鏈接升級到HTTPS。chrome
HSTS是一種可選的安全加強策略,已經由IETF RFC6797中指定。瀏覽器
服務端經過Strict-Transport-Security
響應頭來通知客戶端應用 HSTS協議。緩存
Strict-Transport-Security: max-age=31536000; includeSubDomains
# inclueSubDomains 是可選參數,告知瀏覽器將HSTS策略用到當前域的子域。
一旦瀏覽器承認這個響應頭,知曉訪問這個域名的全部請求必須使用HTTPS鏈接,將會在1年時間內緩存這個約定。安全
當支持 HSTS的瀏覽器承認該響應頭:服務器
由於HSTS策略由客戶端強制執行,有一些前置條件:app
Preload HSTS
細心的你可能發現,HSTS仍是存在一個薄弱漏洞,那就是瀏覽器沒有當前HSTS信息,或者第一次訪問; 或者新操做系統,瀏覽器重裝,清除瀏覽器緩存;HSTS信息的max-age過時;網站
依然須要一次明文HTTP請求和重定向才能升級到HTTPS並 刷新HSTS信息,這一次依然給攻擊者可乘之機,針對以上攻擊,HSTS的應對辦法是在瀏覽器內置一個域名列表,這個列表內域名,瀏覽器都會使用HTTPS發起鏈接,這個列表由Chrome維護,主流瀏覽器均在使用。
在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; } }
若使用 Kestrel 做爲邊緣(face-to-internet) web服務器, 參見下面的服務配置
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 並不生效
這也是開發者在本地啓動時 抓不到 Strict-Transport-Security 響應頭的緣由。
下面兩動圖演示用戶首次、後續 直接輸入域名訪問HTTPS+HSTS站點的過程, 請注意響應碼的差別。
- 動圖1 (瀏覽器無站點HSTS信息): HTTP協議請求----> 返回301,要求重定向使用HTTPS協議 -----> 使用HTTPS協議請求, 被nginx 種下HSTS信息
- 動圖2 (瀏覽器存在站點HSTS信息): HTTP 協議請求----> 307 internal redirect (瀏覽器監測到存在站點HSTS信息,直接更改成HTTPS發起請求)------> 使用HTTPS協議請求
+ 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