分享到朋友圈 1. 点击导航栏右侧按钮。
2. 选择 发送给朋友 或 分享到朋友圈。
收起 捐款给作者

Cherysun’s Tech Cafe

从 GitHub 受到中间人攻击一事再看 HSTS

访问 GitHub 时出现了 ERR_CERT_AUTHORIY_INVALID 错误

两天前,GitHub 遭遇了一场大规模的 MitM 中间人攻击,在中国大陆访问 GitHub Pages 时其证书变为了一份由个人 QQ 邮箱所签发的自签名证书。尽管证书签发者看似是个人所为,但攻击通过骨干网络发起,其影响覆盖几乎所有省份的主要运营商。不过由于 GitHub 启用了 HSTS,主流 web 浏览器均不允许用户忽略证书问题的安全警告,因而避免了后续的不安全访问。

在国内类似问题频出的环境下,HTTPS 和 HSTS 的必要性又要老生常谈,尽管 HTTPS 已经较为主流,但是 HSTS 仍然需要强化,应积极提上日程。

摘要 TL;DR

什么是 HSTS?

HSTS 是 HTTP Strict Transport Security 的简称,即 HTTP 严格传输安全,是一种使浏览器强制通过 HTTPS 访问资源的安全功能,从而降低被劫持风险。HTST 信息通过服务器的响应标头 response header 告知 web 浏览器。

为什么要使用 HSTS?

发出 HTTPS 请求的背后到底发生了什么?

一般地,用户在浏览器中访问某个网址时,很少直接手动输入 HTTPS 协议,通常会直接在地址栏键入 http://foo.com 甚至直接是 foo.com。浏览器则会在发起“每次”请求时,先通过 80 端口使用 HTTP 协议明文向服务器发起请求,服务器在接收到该请求后会向浏览器返回 301 或 302 重定向,紧接着,浏览器再次通过 443 端口使用 HTTPS 协议进行加密访问。

通常,浏览器通过 :80 对某一域名发起请求,服务器将其重定向至 :443

通常,浏览器通过 :80 对某一域名发起请求,服务器将其重定向至 :443
不得不提及的 SSL 剥离攻击

然而这样的通信机制实际上存在某种隐患,例如所谓 MitM Attack(Man-in-the-Middle Attack,中间人攻击)中的一种,即 SSL Stripping Attack(SSL 剥离攻击),攻击者在浏览器通过 80 端口发次第一次明文的 HTTP 请求时就实施劫持,作为中间人一方面通过 80 端口与浏览器通信,另一方面通过 443 端口与服务器进行通信,这样一来就可以嗅探和伪造通信数据。

这意味着,用户一端实际上始终在使用明文与中间人在传输密码等重要数据,并非与服务器直接通信;而中间人利用所获取的完整数据再仿冒用户与服务器进行通信,由于所有数据均是完整的,对于服务器而言也无法识别到中间人的存在。如此,尽管有 HTTPS 的存在,但实际而言通信数据是在裸奔。

SSL Strip 是如何发生的

通常,浏览器通过 :80 对某一域名发起请求,服务器将其重定向至 :443
HSTS 所发挥的防范作用

既然通过 443 端口发起请求前都会先通过 80 端口发起一次请求,这就形成了可能被中间人攻击所利用的漏洞,为了防范该问题,HSTS 应运而生。

当用户在某个浏览器中“首次”访问例如 http://foo.com 的某一网站时,服务器会在响应标头中添加 Strict-Transport-Security 信息通知浏览器,声明该网站禁止使用 HTTP 方式加载,只能使用 HTTPS 发起请求,浏览器也会将该信息报存在本地。这样一来,当访问该域名时,浏览器会在内部发起 307 临时重定向 Temporary Redirect,将 HTTP 请求在内部完成到 HTTPS 的重定向。从表现上来看,意味着浏览器就会将“后续的所有”请求均替换为 HTTPS 请求,不再先向服务器发起 HTTP 请求,从而避免了后续受到 SSL 剥离攻击的潜在风险。

HSTS 仍不完美

尽管 HSTS 规避了每次发起 HTTPS 请求前需要先发起 HTTP 请求所造成的风险,但显然,某个浏览器在“第一次”访问某一网站时,仍然会发起 HTTP 请求,只不过收到带有 Strict-Transport-Security 头的响应后,再将后续请求为 HTTPS。这样还是给攻击者留有可乘之机。例如在不安全的网络环境中使用新设备或使用已清除浏览器缓存的设备上访问时,浏览器尚未保存该网站的 HSTS 信息,“第一次”访问时依然会发起一次明文的 HTTP 请求。

为了消除该隐患,HSTS Preload List(预加载 HSTS)出现了。

预加载 HSTS

未解决浏览器在发起首次请求前不知道网站是否强制使用 HTTPS 的问题,HSTS Preload List(预加载 HSTS)随后出现,这份预加载列表内置于浏览器中,声明了有哪些网站强制使用 HTTPS,如此,浏览器就可以在首次访问这些网站域名时直接使用 HTTPS,不再发起 HTTP 请求,从而填补了上述提及的漏洞。这份列表现在由 Google 维护,Chrome、Firefox、Opera、Safari、IE 11 和 Edge 等主流浏览器均已采用,但是这尚不属于 HSTS 标准的一部分。

HSTS Preload List Submission

如果所访问的域名在预加载列表中,浏览器在通过 HTTP 发起请求时,浏览器首先会发起 307 内部 Temporary Redirect,然后直接通过 HTTPS 进行访问。

有了 HSTS Preload List,浏览器在内部完成 307 重定向,然后直接通过 :443 发起加密请求。

有了 HSTS Preload List,浏览器在内部完成 307 重定向,然后直接通过 :443 发起加密请求。

服务器应如何配置 HSTS

前文说到,HSTS 是以响应标头的形式通知浏览器,因而只需要对网页服务器增加 Strict-Transport-Security 的 header。其语法为:

Strict-Transport-Security: max-age=<expire-time>
Strict-Transport-Security: max-age=<expire-time>; includeSubDomains
Strict-Transport-Security: max-age=<expire-time>; preload
HSTS 响应标头参数说明

max-age=<expire-time>:设置在浏览器收到这个请求后的 <expire-time> 秒的时间内凡是访问这个域名下的请求都使用HTTPS请求,即过期时间。浏览器每次收到新的 response 后都会更新该时间。

includeSubDomains(可选):如果这个可选的参数被指定,那么说明此规则也适用于该网站的所有子域名。

preload(可选):声明是否使用浏览器的预加载 HSTS 列表。尽管这并不属于 HSTS 标准,但已被广泛采用。

以 NGINX 为例

以 NGINX 为例,HSTS 的配置比较简单,在配置文件中添加如下内容:

add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;

当浏览器收到带有 Strict-Transport-Security 的响应标头时,即了解该网站强制使用 HTTPS。其中,max-age=63072000 意味着将过期时间设置为 2 年(63072000 秒);includeSubDomains 存在时意味着该域名下的所有子域名均强制使用 HTTPS,全站不得使用 HTTP 进行访问;preload 即意味着使用浏览器内置的预加载 HSTS 列表。最后的 always 参数表明网页服务器要为所有的响应均设置此 header,包括内部生成的错误响应。也可根据实际需要删除 ; includeSubDomains; preload 这两个可选参数。

可以使用浏览器的 Web Inspector 检查响应中的 Strict-Transport-Security 标头

可以使用浏览器的 Web Inspector 检查响应中的 Strict-Transport-Security 标头

完整 NGINX 配置示意如下所示:

server {
  listen 443 ssl;

  ...

  add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;

  ...
}
将域名加入预加载 HSTS 列表

访问 https://hstspreload.org 并输入所要提交的域名,检查其合法性。在提交前,需要确认满足以下 4 点要求:

  1. 网站具有有效的证书。
  2. 如果网页服务器有在监听 80 端口,那么需要在该主机上将 HTTP 重定向到 HTTPS。
  3. 所有子域名都要使用 HTTPS。特别是,如果子域名有 DNS 记录存在,那么 www 子域名必须支持 HTTPS。
  4. 添加 HSTS 响应标头,并满足下列要求:
    • max-age 必须至少是 31536000 秒(1 年)。
    • 必须指定 includeSubDomains 参数。
    • 必须指定 preload 参数。
    • 如果该 HTTPS 网站存在其他重定向,那么重定向也必须具有 HSTS 头。

按照上述要求实施后,即可在上述页面检查合法性并提交所拥有的域名。

回到 GitHub 受到中间人攻击一事

本次针对 GitHub 发起的中间人攻击,由于 GitHub 使用了 HSTS,因而攻击者难以采取 SSL 剥离手段,而是直接使用证书欺骗的方法,伪造 GitHub 证书,试图欺骗浏览器。然而,一般地,当浏览器发现不可信证书后,会直接向用户展示安全警告,提示证书问题以阻止访问,不过有不少用户可能仍然会选择忽略浏览器的安全警告,继续不安全的访问,这时候仍然存在安全风险。但也是得益于 HSTS,主流浏览器对于启用 HSTS 网站的安全警告均作出不可忽略的设定,彻底阻止用户的进一步访问。因而当 GitHub 受到证书欺骗的中间人攻击时,用户只不过无法进行访问,但实际上并不会产生实际的安全问题。

对于启用 HSTS 的网站,用户无法忽略 web 浏览器的完全警告而继续访问

对于启用 HSTS 的网站,用户无法忽略 web 浏览器的完全警告而继续访问

Qualys SSL Labs 的 SSL Pulse 服务持续监测 Alexa 全球访问量最高的 15 万个启用 SSL / TLS 的网站,截至 2020 年 3 月,只有 23.5% 的网站支持 HSTS,仅 30,000 余个网站。

SSL Pulse 监测的 HSTS 采用率,2020 年 3 月

SSL Pulse 监测的 HSTS 采用率,2020 年 3 月

参考资料

  1. Strict-Transport-Security – HTTP – MDN,https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security
  2. HTTP Strict Transport Security (HSTS) and NGINX – NGINX,https://www.nginx.com/blog/http-strict-transport-security-hsts-and-nginx/
  3. HSTS Preload List Submission,https://hstspreload.org
  4. Qualys SSL Labs – SSL Pulse,https://www.ssllabs.com/ssl-pulse/
使用微信扫描下方二维码,然后 发送给朋友分享到朋友圈

感谢您的支持与贡献

您的捐款将使您阅读到的内容变得更好。

支持微信支付和支付宝。

在微信中扫描二维码 在支付宝中扫描二维码

感谢您的支持与贡献

您的捐款将使您阅读到的内容变得更好。

触摸并按住二维码,选择识别图中二维码

触摸并按住二维码