HSTS – what, why and how

HSTS,全称是HTTP Strict Transport Security(HTTP严格传输安全),是一种可以让浏览器强制使用https来与网站进行通讯的策略。通俗而形象的解释下就是如果一个网站(比如本站)使用了HSTS,那么一旦你访问过https://xia.moe,那么你就再也无法访问http://xia.moe了。对,哪怕有其他人劫持了你的网络,也无法让你访问本站的http版本了。

为什么要用HSTS?让我们先来看看为什么要用https。我们知道http是明文传输的(神马?你不知道?那你现在知道了。。。),这意味着互联网上的其他人可以看到你传输的一切信息(窃听),包括你的密码。这并不是最糟糕的,可能有一个恶意的第三者在你和网站中间(MIM Attack,中间人攻击),伪造了网站的页面并展示给你来达到ta的目的,比如钓鱼。为了解决这些问题https出现了,它能确保你所访问的网站真的是它,而不是其他人伪造的,同时你们之间的信息也都是加密传输的,这就同时解决了中间人攻击和监听两大问题。

然而,不是所有用户,或者应该说大部分用户都没有意识会主动去访问https版本的网站,怎么办?有人说很简单,当我发现有人通过http来访问我的时候,我就把ta重定向到我的https版本即可。

if (!isset($_SERVER['HTTPS'])) {
  header('Status-Code: 301');
  header('Location: https://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']);
  exit;
}

重定向有时候可能不够那么优雅,有人也许会选择把自己网站内的所有连接都替换为https的,这样子用户自然就访问了加密的版本。听上去很完美,是么?让我们设想一下,一个无知的用户进入了http://www.example.org/,然后你把ta重定向或引导到https://www.example.org。这时候邪恶的第三者出现了,它把你返回的内容(因为用户请求的时候用的是http,所以这次请求依然是明文的,可以被篡改的)里所有https都替换成http(SSL剥离攻击),你的完美计划就破灭了。HSTS正是为了解决这一个问题而生,只要用户一旦访问过https,那么后面的访问无论如何都会使用https的版本。除此之外,HSTS还能够不再允许用户忽略警告(对于一般的https,当证书无效,或者说不是那么的安全(比如自签名的证书)时,浏览器会给出警告,但很多用户都会很随意的忽略这个警告)。

那么如何开启HSTS呢?很简单,只要在返回的header中包含Strict-Transport-Security字段即可。以apache为例,编辑httpd.conf,加入以下行:

LoadModule headers_module modules/mod_headers.so
<VirtualHost *:443>
    Header always set Strict-Transport-Security "max-age=63072000"
</VirtualHost>

这里的失效时间是两年,但是不用担心,因为每次访问都会包含这个相应头,因此失效时间会被不断刷新。除了失效时间,还有两个参数includeSubDomainspreload,具体的解释可以参考MDN文档需要注意的是,Strict-Transport-Security必须在https请求中返回才有效,如果在http请求中返回则会被忽略。

可能有机智的读者已经发现问题了,HSTS对于http无效,那么岂不是对于一个从没访问过我网站的用户来说,只要ta首次访问的不是https,那么ta依然有风险?很遗憾,的确是这样子的,但这问题并非没有解决途径。一种解决方案是浏览器预置HSTS名单,目前firefox、chrome、edge、IE都已经支持了这一特性;另外一种解决方案是在域名记录里添加相应信息,但这一方案目前还没得到普及。

如果不是独立主机(比如本站)是不是就无解了呢?当然不是,以php为例,找个好地方(全局性的,尽可能早的)地方加入以下代码即可。

if (isset($_SERVER['HTTPS'])) {
  header('Strict-Transport-Security: max-age=63072000');
}

发表评论

电子邮件地址不会被公开。 必填项已用*标注