0x00 绪论

在学习和使用任何技术框架的时候,难免会碰到各种各种的问题,这些问题也许微不足道,但是依旧存在学习的必要,在闲暇时写写随笔,做做笔记也是好的。

0x10 HSTS

起因是这样的,因为我使用halo博客也有一段时间了,因此推荐给我朋友使用,然后我朋友也是兴致勃勃的注册了域名,备了案,然后开始搭建。在工作都完成之后。我建议我朋友给网站配置证书,这样就是安全访问了。于是,就使用certbot拉取了主站的免费证书。然后我朋友又搭建了另一个mqtt的服务器,通过子域名访问,该子域名未配置证书。刚开始,访问还是好好的,然后突然就无法访问了,显示为不安全的连接,图片来自网络,当时忘截图了,显示结果是一样的,

刚开始碰到这个问题,没有注意到HSTS,只是以为nginx没有配置好,就是检查配置,反复测试。最后测出来结果如下:

  • 新开无痕窗口,单独访问子域名,正常访问

  • 新开无痕窗口,先访问Halo(主域名),再访问子域名,显示类似上图的信息。

最后我才注意到HSTS的提示信息,查阅资料后,确定是它搞得鬼。

0x11 HSTS介绍

在说HSTS之前需要说明https,熟悉前端的朋友都会知道,主流的前端服务通信协议分为两个,http个https,这也对应了80和443两个端口。

https就是基于http的加密协议,目的就是为了保证安全。但是在建立连接的过程,第一次请求通常都是http请求,然后由服务器返回301重定向到https。

但是这么做呢,可能出现问题:建立HTTPS连接之前的这一次HTTP明文请求和重定向有可能被攻击者劫持,解决这一问题的思路就是如何避免出现这样的HTTP请求。我们期望的浏览器行为是,当用户让浏览器发起HTTP请求的时候,浏览器将其转换为HTTPS请求,直接略过上述的HTTP请求和重定向,从而使得中间人攻击失效,规避风险。

因此,HSTS应运而生,HSTS,即HTTP Strict-Transport-Security。 当站点通过 HTTPS 运行的时候,服务器通过返回一个响应头部 Strict-Transport-Security ,强制浏览器以后使用 HTTPS 进行通信

HSTS最为核心的是一个HTTP响应头(HTTP Response Header)。正是它可以让浏览器得知,在接下来的一段时间内,当前域名只能通过HTTPS进行访问,并且在浏览器发现当前连接不安全的情况下,强制拒绝用户的后续访问要求。

HSTS Header的语法如下:

Strict-Transport-Security: <max-age=>[; includeSubDomains][; preload],例如:

  • Strict-Transport-Security: max-age=<expire-time>

  • Strict-Transport-Security: max-age=<expire-time>; includeSubDomains

  • Strict-Transport-Security: max-age=<expire-time>; preload

其中:

  • max-age是必选参数,是一个以秒为单位的数值,它代表着HSTS Header的过期时间,通常设置为1年,即31536000秒。

  • includeSubDomains是可选参数,如果包含它,则意味着当前域名及其子域名均开启HSTS保护。

  • preload是可选参数,只有当你申请将自己的域名加入到浏览器内置列表的时候才需要使用到它。

重点就是includeSubDomains,此次的问题就是在访问halo时,自动返回了includeSubDomains参数,导致了该问题

0x12 解决办法

根据网上的资料和实际操作情况,我总结如下几种解决办法

  • 在浏览器设置中清除HSTS缓存

  • 给子域名配置证书

  • 想办法关闭HSTS或者返回Strict-Transport-Security不带includeSubDomains参数

  • 将halo部署到子域名,而不是主域名

清除浏览器HSTS缓存

例如我常用的edge流量器,访问 edge://net-internals/#hsts 输入域名即可删除

这种方法呢一般为开发测试时使用,使用该方法需要每访问一次删除一次,繁琐不堪,显然不是首选。

给子域名配置证书

因为HSTS会导致访问http强制跳转到https,那么只要给子域名配置证书,让其可以通过https访问,问题自然就解决了,目前使用的就是这种方法

关闭主站的HSTS功能

一开始我以为这个功能是nginx自动加的,测试后发现应该是halo后端的功能。于是我在halo的GitHub找到了相关issues,#4943

从这个issue中可以得出,目前没有设置HSTS的开关,也没有设置HSTS参数的可选项。但是开发者同样给出了解决方法,在Nginx的配置文件中,删除:proxy_set_header X-Forwarded-Proto $scheme; ,没有中间件的服务器呢,前端是直接连接到后端的,后端可以知道通信的所以信息,包括协议,请求头等等,在使用nginx之后,后端不直接与前端通信,因此它只知道它与中间件的连接情况,不清楚中间件与前端的连接情况,因此需要中间件做转发。因此删除该行配置后,nginx就不会转发协议内容,halo在没有收到https请求的情况下不会响应HSTS参数,也算是关闭了该功能。

后续我在该issue下追加了提问,同时开发者也修复了该问题,见#5956

目前在最新的2.15.2版本中未发布该修复,推测可能会在2.15.3中发布

因此,只需要跟新版本就能解决该问题,人生~易如反掌~

将Halo部署在子域名

既然HSTS会影响该域名及其子域名,那么我一开始就将halo部署在子域名就好啦。例如blog.xxx.cn。其他服务就部署在各自的子域名,例如mqtt.xxx.cn,这样就不会互相影响。

该方法不需要考虑其他子域名的证书问题,也不用考虑nginx配置或者halo版本的问题,倒也算是一个不错的解决方案。


To be continued~