大部分同学应该都知道 HTTP 协议的网站是不安全的,存在中间人劫持的情况,因此我们平常开发的网页都会将 HTTP 协议升级为 HTTPS,以确保不会被中间人劫持。
注:本文不涉及 HTTPS 的实现原理以及中间人劫持的概念,不了解的同学先去恶补
可是你们以为这样就绝对安全了吗?我们想想下面的场景:
通常情况下,我们打开一个普通的网站可能是通过以下几个方式:
- 直接点击收藏栏
- 通过搜索引擎找到
- 直接输入域名
当采用 直接输入域名 的方式时,如下图所示:
这时候我们并没有告诉浏览器当前请求的网站协议是https,然而我们最终打开的还是 https 协议的百度网站。这是为什么呢?
其实就是重定向帮我们做了肉眼看不见的事情,具体流程见下图
那么这个过程中第一步就会涉及名文的传输,因此有了被中间人攻击的机会,所以我们该如何避免这种情况的出现呢?答案就是本文需要介绍的 HSTS
HSTS
MDN 对 HSTS 的定义非常直白
HTTP Strict Transport Security
(通常简称为HSTS)是一个安全功能,它告诉浏览器只能通过HTTPS访问当前资源,而不是HTTP。
通过定义我们可以画出下面这样的流程图
当发起 http 的请求,不经过服务器直接变成 HTTPS 将请求发出去。
具体怎么才能让 HSTS 其作用呢?我们接着看。
Strict-Transport-Security
通过给https协议的网站的response header配置Strict-Transport-Security
Strict-Transport-Security: max-age=<expire-time>; includeSubDomains(可选); preload(可选,非标准)
每个属性的定义如下:
- max-age=<expire-time> -- 在浏览器收到这个请求后的<expire-time>秒的时间内有效。
- -- 如果这个可选的参数被指定,那么说明此规则也适用于该网站的所有子域名。
- preload -- 谷歌维护着一个 HSTS 预加载服务。按照指示成功提交你的域名后,浏览器将会永不使用非安全的方式连接到你的域名。虽然该服务是由谷歌提供的,但所有浏览器都有使用这份列表的意向(或者已经在用了)。但是,这不是 HSTS 标准的一部分,也不该被当作正式的内容。
我们看到百度的网站也设置了Strict-Transport-Security。
表示在172800秒的时间内访问百度的主页都是以https的形式,不过他并没有设置includeSubDomains这个属性。
细心的同学可能发现了,有一种情况下还是没办法避免中间人劫持。那就是,在用户第一次访问网站并且使用 http 协议的情况下,如果真要全面防止只能通过给域名添加 preload 的方式。具体方法请参加 MDN 添加preload
总结
有了上面的基础,让我们总结一下三种首次访问的情况
-
没有HSTS
- 浏览器发起http请求
- 服务端重定向到https
- 浏览器发起https请求
-
有HSTS,没有preload
- 浏览器发起http请求
- 服务端重定向到https
- 浏览器发起https请求
- 服务器收到https请求,返回数据的同时会添加 strict-transport-security的header,配置参见上文。每次https请求都会刷新这个过期时间。
-
有HSTS以及preload(最佳实践)
- 浏览器发起http请求
- 由于存在preload,浏览器会主动将链接升级为https。
最后我们应该注意,在生产环境下使用 HSTS 应当特别谨慎,因为一旦浏览器接收到HSTS Header(假如有效期是1年),但是网站的证书又恰好出了问题,那么用户将在接下来的1年时间内都无法访问到该网站,直到证书错误被修复,或者用户主动清除浏览器缓存。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。