Https连接
Https通过加密传输和身份认证保证了http协议传输过程的安全性,然而这并不意味着你开启了https网站就绝对安全了。大部分用户都很少直接在地址栏输入https://,而是直接输入网址。此时浏览器默认发起http请求,再由服务端进行30x重定向(通常是301永久重定向)到https。如下图:
SSL剥离攻击
用户第一次发起的是http请求,存在被中间人劫持的风险。黑客可以用下图的方式劫持用户请求,阻止浏览器与服务器创建HTTPS连接。
1.用户向服务器发起http请求;
2.黑客劫持了这个http请求;
3.黑客向服务器发起相同的https请求,服务器返回数据;
4.黑客把返回的数据作为http请求的响应返回给用户;
5.用户拿到响应数据,其实所有通信内容(包括密码等敏感数据)已经被黑客知道了;
这种典型的中间人攻击方式被称为“SSL剥离攻击”,由Moxie Marlinspike在2009年黑帽大会上发表的《New Tricks For Defeating SSL In Practice》演讲中公开。
HSTS原理及实践
想要尽可能避免SSL剥离攻击,就得让浏览器一开始就发起https请求,而不是默认发起http请求。这个安全策略机制就是“HTTP Strict Transport Security”(HTTP严格传输安全),缩写HSTS。网站一旦启用HSTS策略,浏览器会强制使用HTTPS网站进行通信,以减少会话劫持风险。
服务器开启HSTS的方法很简单。当浏览器发起Https请求的时候,在响应头中增加Strict-Transport-Security字段。你可以在框架层添加,也可以nginx配置增加一行:
add_header Strict-Transport-Security "max-age=31536000";
浏览器收到这个字段后,在后续一段时间内向这个域名发起的任何请求,都必须采用https来发起连接。本博客已经开启HSTS,您可以打开浏览器的控制台查看响应头作为例子。HSTS Header的语法如下:
Strict-Transport-Security: <max-age=>[; includeSubDomains][; preload]
-
max-age:必选参数,代表着HSTS Header的过期时间,以秒为单位,比如设置1年,就是31536000。
-
includeSubDomains:可选参数,如果包含它,则当前域名及其子域名均开启HSTS保护。
-
preload:可选参数,表示申请将自己的域名加入浏览器内置列表,下文再详细介绍。
需要特别注意:
-
在http请求的响应里带Strict-Transport-Security不会生效。
-
标记了HSTS的网站,如果服务器的TLS证书无效,用户不能选择忽略浏览器的警告继续访问网站。这还可以避免伪造证书的风险。
保护首次请求
HSTS只能在第二次请求的时候生效,不能保护首次请求,因为首次访问的时候浏览器还未收到HSTS。解决这个问题当前有两个方案,一个是把HSTS信息加入到DNS记录中,但这需要保证DNS的安全,目前应用并不广泛;另一个是把HSTS信息加入到浏览器中,即浏览器的Preload List。
Google Chromium维护的HSTS Preload List项目,是目前业界的事实标准,Chrome/FireFox/Safari/IE都在使用。一旦加入这个列表,以后浏览器直接输入你的网站域名,首次请求就默认走https协议。
加入Preload List的方式很简单,访问https://hstspreload.org/,输入你的网站域名即可。添加的域名需要满足以下要求:
-
根域名和所有子域名均使用https协议并具备有效的证书;
-
对http请求提供重定向;
-
根域名的HTTP响应头中,加入HSTS Header,必须包含includeSubDomains和preload参数,过期时间最短不少于18周(10886400秒)。
总结
SSL剥离攻击可以劫持用户发起的http请求,让服务端的https配置形同虚设。因此需要开启HSTS,强制客户端使用https连接,保障网站的安全。
参考文献
本文未经许可禁止转载,如需转载关注微信公众号【工程师加一】并留言。