HSTS 详解

Fall
当网站全站启用 HTTPS 后,通常我们会将 HTTP 重定向至 HTTPS,以强制用户使用 HTTPS 协议。但用户的第一次浏览网站且使用的 HTTP 协议时有被中间人劫持的风险。目前可以通过 HSTS 来避免被此类风险。

HTTPS 降级劫持流程图

HSTS 简介

HSTS,全称 HTTP Strict Transport Security,是 IETF 发布的一种 web 安全机制。采用 HSTS 的网站将通知浏览器始终使用 HTTPS 来连接网站,从而不需要用户手动在 URL 地址栏中输入 https://,以减少中间人劫持的风险。

HSTS 响应头(Response Header)

网站启用 HSTS 只需在 HTTPS 响应头中加入Strict-Transport-Security即可。

1
2
3
4
Strict-Transport-Security: max-age=<expire-time>
Strict-Transport-Security: max-age=<expire-time>; includeSubDomains
Strict-Transport-Security: max-age=<expire-time>; preload
Strict-Transport-Security: max-age=<expire-time>; includeSubDomains; preload
  • max-age=<expire-time>:秒,设置在浏览器收到此响应后秒的时间内,这个域名下的所有请求都使用 HTTPS。
  • includeSubDomains:可选,该网站的所有子域名也都使用 HTTPS。
  • preload:可选,查看浏览器内置的 HSTS Preload List 以获取网站是否支持 HSTS。

HSTS 流程

HSTS 流程图

HSTS 缺陷

如上图「HSTS 流程图」所示,用户使用 HTTP 协议「首次或未在本地查询到网站的 HSTS 缓存」访问某网站时,仍存在被中间人劫持的风险。所以 HSTS 并不是 HTTP 中间人劫持的完美解决方案。

那么哪些情况浏览器不能在本地查询到网站的 HSTS 缓存?

  • 首次访问该网站
  • 浏览器的缓存被清空
  • 长时间未访问该站且该站 HSTS 的缓存时间已失效
  • 使用了新的浏览器
  • 使用了新的设备
  • 。。。。。。

为了解决此问题,浏览器厂商提出了 HSTS Preload List 方案。

HSTS Preload List

虽然 HSTS 可以很好的解决 HTTPS 降级劫持,但是对于 HSTS 生效前的首次 HTTP 请求,依然无法避免被劫持。
于是浏览器厂商们提出了 HSTS Preload List 方案来解决此问题。
即在浏览器中内置一份可以定期更新的 HSTS 列表,对于列表中的域名,强制使用 HTTPS 协议。

现在 HSTS Preload ListGoogle Chrome 维护。
当下主流的浏览器(Chrome, Firefox, Opera, Safari, IE 11 and Edge)所使用的 HSTS Preload List 都是以此列表为基础。

  • Chrome & Chromium 的 HSTS 列表:https://www.chromium.org/hsts
  • Firefox 的 HSTS 列表:nsSTSPreloadList.inc

站长可在https://hstspreload.org/申请将网站加入HSTS Preload List

HSTS 部署

HSTS 需要在服务器中进行设置

  • 网站必须使用 443 端口。
  • 网站必须使用域名,不能是IP。
  • 网站全站开启 HTTPS

Caddy

1
2
3
4
5
6
7
8
9
10
11
http://g.com {
redir https://{host}
}
https://g.com {
root /var/www/
gzip
cache
header / {
Strict-Transport-Security "max-age=63072000; includeSubdomains; preload"
}
}

Nginx 上启用 HSTS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
:~$ vim /etc/nginx/conf.d/g.com.conf
server {
listen 443 ssl;
server_name g.com;
add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload";
...
}

server {
listen 80;
server_name g.com;
return 301 https://g.com$request_uri;
...
}

测试设置是否成功

可以使用浏览器自带的开发者工具curl 验证。
只要网站的应答头里包含Strict-Transport-Security字段,就说明设置成功了。

Curl

1
2
3
4
5
6
7
:~$ curl -I https://g.com
HTTP/2 200
accept-ranges: bytes
content-type: text/html; charset=utf-8
last-modified: Thu, 26 Sep 2019 15:42:55 GMT
strict-transport-security: max-age=63072000; includeSubdomains;preload;
...

Firefox 开发者工具[F12]

查看https://hstspreload.org/是否启用 HSTS

Firefox Web Developer


References:

  • HTTPS详解
  • Mozilla.org
  • wikipedia
  • HSTS Preload
  • hi-linux