IT技术博客大学习 共学习 共进步

部署 HSTS 提升网站安全性

Becomin' Charles 2017-03-01 23:17:44 浏览 2,782 次

什么是 HSTS?

HSTS 是 HTTP Strict Transport Security 的缩写,字面意思就是“HTTP 严格传输安全”。在 2012 年 11 月发布了 RFC 文件。其实质,是通过服务器和浏览器配合起来,强制用户使用安全连接来访问服务器。

HSTS 大致原理是,服务器在 SSL 连接的网站请求返回中,带上一个响应头(Response Header)信息,要求浏览器使用强制安全,则在下一次用户访问此域名时,浏览器会自动探测用户是否使用了安全连接,如果没有的话,自动在浏览器端重设了 URL,通过安全连接来访问服务器。避免了用户通过不加密的协议与服务器进行通信。

设计 HSTS 的目的是什么?

每当出现一种安全机制,我们都要想想这背后的目的是什么。其实我也并不知道,接下来直接谈谈我的个人想法好了。目前为止,我们所用到的常见浏览器,Chrome,Firefox,IE,都是没人使用非加密通信的 HTTP 协议访问目标网站的,除非用户手动输入来指定使用的协议是 ,浏览器才会跟服务器进行加密通信。

在这种情况下,很多用户的使用习惯是键入域名来访问目标网站,那么浏览器就会自动选用 HTTP 协议,如果网站提供 HTTPS 服务,服务器一般会返回 302,要求用户重新使用 HTTPS 连接访问网站,以获得加密的连接通信。这种场景无论是对用户而言,还是对网站服务而言,都是自然而然的选择。

在现今的网络环境下,越来越多网站提供了全站 HTTPS 服务,但是,用户的习惯已经养成,并不会因为网站提供了 HTTPS 服务,就会每次输入网址的时候手动输入协议,毕竟用户根本不懂技术。那我们就要问了,如果用户每次都是先访问 HTTP 服务,然后经由服务器的跳转再进入 HTTPS 服务可不可以呢,当然是可以的,但是,这么做是有风险的。如果用户身处一个有嗅探或者过滤的网络,那么用户首次连接网站服务的时候,其会话可能就会被窃取,其身份可能会被恶意伪装。如果,有恶意的攻击者,甚至可能在这个过程中,施行中间人攻击。届时,用户根本不知道自己的一切,已经被人看光了,还以为自己在进行安全的 HTTPS 通信呢。

于是,必须有一种浏览器厂商和服务商共同提供的机制,帮助用户直接选择使用 HTTPS 服务,避免跳转导致的弊端,我们就有了 HSTS,这个协议的作用就是服务器通知客户端,以后访问本服务的时候,一律使用 HTTPS 进行访问。

HSTS 的使用

从 2012 年发布至今,主流的浏览器基本都已经支持了。开启 HSTS 也是非常简单的。只要在 HTTPS 服务的返回的 Response Header 里面添加一条 HSTS 的声明就可以开启这个特性了。如下是一个 Nginx 下的配置范例。其原理只是标准的 HTTP Header 而已,其他的 Web 服务器的配置,就不再赘述了,可以查阅相关文档。


add_header Strict-Transport-Security"max-age=31536000; includeSubdomains; preload";


这行配置,要增加到提供 HTTPS 服务的段落里面,浏览器如果在访问一个 HTTPS 的网站的时候,收到了这个响应头信息,会首先校验服务器的证书链,如果都正确无误,会把这个服务器的域名加入到本地一个“已知主机列表”中,这是一个类似哈希索引的东西,以后访问任何 HTTP 的服务的时候,都会查询此索引,一旦发现查到了,就在用户的电脑本地直接产生一个 307 内部跳转(Chrome 的行为),让用户连接到对应的 HTTPS 服务上。

因为,整个机制很大一部分依赖客户端的行为,所以,我们必然面临一个问题,就是下发到客户端的参数是不易维护的。上面展示了这个特性涉及到的三个参数。其中必填的参数是 max-age 这个参数指定了一个 HSTS 主机的生效时间,单位是秒,上面填写的时间 31536000 是一年时间。如果网站的 HTTPS 临时无法访问,收到过 HSTS 的浏览器,也将拒绝访问网站提供的 HTTP 服务,也即,优雅降级的可能性被消除了,所以在使用的时候要做好运维工作和风险评估。设置合理的 max-age 也是很必要的。如果设置得太短,增加了用户暴露在风险中的机会,如果设置得太长,则一定程度提高了网站运维的风险。

第二个参数 includeSubdomains 是可选的参数,主要是声明当前 HSTS 主机域名的所有子域也都是 HTTPS 服务,这个参数的设置,会有一定的风险,可能导致有些网站的子域不可用,如果不能确定网站的所有子域都是 HTTPS 服务,不应该添加这个参数,毕竟有些网站,业务还没有扩张,一开始在根域设定了这种参数后,导致子域都必须 HTTPS 了,那可就麻烦了。例如,一开始你购买了 company.com 的域名开始提供服务,到了后期,发现流量上涨,开始部署 CDN,这时候,你发现,cdn.company.com 这个域名已经被加入用户 HTST 里面的,这就很糟糕了。

第三个参数,说得是预加载特性。从上面所有的行为里,我们可以看到,即使使用了这个策略,用户至少还要有一次机会暴露在非安全的网络之下,虽然被入侵的概率已经很低了,但是对于一个服务来说,但是拦截首次访问服务的新客,也可以给服务方造成巨大损失。能不能彻底杜绝这种可能性呢?于是就有了预加载服务,网站服务首先把自己的域名提交给浏览器的厂商进行认证,添加到 Preload 列表里,这样,早在用户听说你的网站域名之前,浏览器里已经预置了这个域名。这无异一柄双刃利剑,一方面提供了近乎绝对的安全策略,另一方面,极大限制了网站的方案选择。Preload 列表影响范围更广,清楚更加麻烦。

如果服务方希望清楚掉 HSTS 的话,需要将 max-age 设置为 0,但是,这个尴尬就跟客户端分发是一样的,如果用户在此期间没有访问你的网站,那么 HSTS 的记录是删不掉的,所以说,max-age 才显得可贵,切不能设置得时间太长。

总结

总体来说,使用安全连接协议,对用户来说,对服务提供商来说,都是好事。在现今这个网络环境下,还是尽量使用 HSTS 吧,尽快提升互联网整体环境的安全。这已经是大势所趋,苹果,微信,都在强势推广 HTTPS,而像 Let’s Encrpyt,中国的七牛,腾讯云等,也都提供了免费的一年期 SSL DV 证书给每个用户,所以,放心大胆的开启 HSTS 策略吧。

建议继续学习

  1. 腾讯执行的感悟(安全方向) (阅读 5,924)
  2. 微博架构与平台安全演讲稿 (阅读 5,623)
  3. 如何让ssh登录更加安全 (阅读 5,602)
  4. IT从业人员需要知道的安全知识(1) (阅读 4,704)
  5. 为flash建立socket安全策略文件服务器 (阅读 4,681)
  6. php.ini安全配置及使用说明 (阅读 4,461)
  7. 查看你服务器的安全性 (阅读 4,284)
  8. 淘宝网:前端安全须知 (阅读 3,801)
  9. Mysql 安全 (阅读 3,683)
  10. jQuery之保证你的代码安全 (阅读 3,441)