今天做项目的时候,由于后台同学的失误,将原本接口中HTTPS协议的接口,弄成了HTTP,导致了一个奇怪的问题:一个接口在我的浏览器上可以访问,在别人的浏览器上无法返回数据. 结果经过一番排查,发现我的接口每次发送请求,都默认请求了三次.
第一次和第二次接口返回为
第三次接口返回为
最后在网上看到这样一篇文章,文章中有对该属性的详细介绍:
The server you are trying to connect with uses strict-transport-security (HSTS) to ensure https only is used with this site rather than the default http.
This means if you enter http://www.servername.com then Chrome will automatically convert this to https://www.servername.com.
This is a security feature to prevent use of http, which is unencrypted and which can be read and altered by a hacker. This can be set by the server telling Chrome (via a special HTTP Header sent in response to requests) that it uses HSTS. This setting is then cached by Chrome for the given amount of time as defined in the max-age value in that header. Additionally the site owner can submit their site to a preload list that is automatically included in Chrome - which protects even the first visit as normally you need to visit the site to receive the header to activate this.
The way Chrome shows this in the network tab is by creating a dummy 307 response with a redirect to the https version of the address. But that's a fake response and is not generated by the server - the reality is Chrome did that internally before the request even went to the server.
To clear this setting for a site you can type the following into Chrome's URL field: chrome://net-internals/#hsts
and then search for your site and delete it. You may also set this at a top level domain and include subdomains so you may need to delete from there. Alternatively you can just alter your server config to publish the header with a max-age of 0 and revisit the site to clear this, then stop publishing the header, which can be helpful for other browsers where it's not quite as easy to clear this.
Note you cannot clear this setting if a site is on the preload list as this is embedded in the web browser's code. The site owner can submit a request to be removed from the preload list but this takes several months to go through the release cycle for Chrome and no defined timeline for other browsers. Chrome also provides no way to override preloaded settings - for security reasons.
根据介绍可以看出来,当我们进入到chrome://net-internals/#hsts页面
经过查询,果然我所访问的域在列表当中,所以当我的http请求时,浏览器通过解析发现该域名存在,因此需要浏览器自行对这个request进行了处理:
The way Chrome shows this in the network tab is by creating a dummy 307 response with a redirect to the https version of the address. But that's a fake response and is not generated by the server - the reality is Chrome did that internally before the request even went to the server.
- 所以前两次请求是浏览器本身自己做的,第三次请求才是真实的请求.
- 当我们删除bizprodmng.xxxx.com这个域之后,我的浏览器也会发生错误,访问不到数据.
问题来了
那我的浏览器是什么时候记录下这个domain,知晓需要将该domain的请求协议由HTTP转化为HTTPS的,,而他人的浏览器(版本相同)并没有转化协议,因此使用HTTP协议请求了该接口,返回的结果如下:
- 301 Moved Permannently (永久移除)
- 请求的URL已移走。Response中应该包含一个Location URL, 说明资源现在所处的位置.
- 具体是因为什么原因导致我的浏览器中记录了这个域名呢?
- 进入到chrome://net-internals/#hsts页面,删除掉浏览器中缓存的域名
当我们显式的访问 https://bizprodmng.xxxx.com 的时候,登录成功后,返回的response头如下:
我们发现访问成功的响应头里面有STS的痕迹:
HSTS 是一个响应头,格式如下:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload;
- max-age,单位是秒,用来告诉浏览器在指定时间内,这个网站必须通过 HTTPS 协议来访问。也就是对于这个网站的 HTTP 地址,浏览器需要先在本地替换为 HTTPS 之后再发送请求
- includeSubDomains,可选参数,如果指定这个参数,表明这个网站所有子域名也必须通过 HTTPS 协议来访问
- preload,可选参数,预加载到浏览器缓存
- HSTS 这个响应头只能用于 HTTPS 响应;网站必须使用默认的 443 端口;必须使用域名,不能是 IP。而且启用 HSTS 之后,一旦网站证书错误,用户无法选择忽略。
同时,当我再次进入到chrome://net-internals/#hsts页面,搜索bizprodmng.xxxx.com
这个域的时候.
结论:
当我在开发过程中显式的访问了 https://bizprodmng.xxxx.com 这个站点并且登录成功之后, 这个站点的登录成功返回头中添加了开启hsts的响应头字段:
Strict-Transport-Security: max-age=31536000
,因此我的浏览器记下了这个接口的domain.用户并没有显式的访问该domain,因此不会有HSTS记录,所以访问失败无法获取服务器接口数据.