本文是《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