本文详细介绍了HSTS的概念、作用、工作原理、以及如何设置HSTS。同时,结合HTTPS和HSTS安全机制,提高数据通信的安全。

HTTP与HSTS

用户在访问某个HTTPS网站时,往往在浏览器中直接输入网站域名,如:www.example.com,而不是输入完整的URL,如:https://www.example.com,但浏览器依然能正确的使用HTTPS发起请求。这种客户体验多亏了服务器和浏览器之间的互相协作。

那这一切是否就是安全的呢? 其实不然。由于在建立起HTTPS连接之前存在一次明文的HTTP请求和重定向,使攻击者可以以中间人的方式劫持这次请求,从而进行后续的攻击(如:窃听数据、篡改请求和响应、跳转到钓鱼网站等)。

那么如何避免HTTPS建立连接之前的那次明文的HTTP请求和重定向,从而防止被中间人攻击,规避风险呢?有没有可能当浏览器发起HTTP请求时,浏览器将其转换为HTTPS请求,直接略过上述的HTTP请求和重定向呢?这就需要启用HTTP Strict Transport Security(HSTS)机制了。

什么是HSTS

HTTP Strict Transport Security(HSTS)是一种Web安全策略机制(web security policy mechanism)。

HSTS最早于2015年被纳入到ThoughtWorks技术雷达,并且在2016年的最新一期技术雷达里,它直接从**评估(Trial)阶段进入到采用(Adopt)**阶段,这意味着ThoughtWorks强烈主张业界积极采用这项安全防御措施,并已经将其应用于自己的项目。

HSTS最为核心的是HTTP响应头(HTTP Response Header),其格式为:

Strict-Transport-Security: max-age=XXX; includeSubDomains; preload

这表明,在接下来的一段时间内,浏览器只要向当前域名或其子域名发送HTTP请求,其通信必须采用HTTPS来发起连接。其中:

  • max-age是必填参数,是一个以秒为单位的数值,它代表着HSTS响应头的过期时间,通常设置为一年,即31536000秒。
  • includeSubDomains是可选参数,如果包含它,则意味着当前域名及其子域名均开启HSTS保护。
  • preload是可选参数,只有当你申请将自己的域名加入到浏览器内置列表时,才需要使用到它。关于浏览器内置列表,参阅本文下方更多信息章节。

HSTS作用

HSTS的作用是强制客户端(如:浏览器)使用HTTPS与服务器创建连接,用户无需手动在URL地址栏中输入HTTPS,浏览器始终保持HTTPS链接访问网页。

同时,在启用HSTS安全机制后,它可以做到:

  • 浏览器强制拒绝不安全的链接
    在没有HSTS保护下,当浏览器发现当前连接不安全时,浏览器会警告用户,但是却又允许用户继续不安全的访问。但在启用HSTS保护下,当浏览器发现当前连接不安全时,除了会警告用户外,它还将彻底阻止用户继续访问此网站。如下图所示:
    浏览器彻底阻止用户继续进行不安全的访问
  • 设置HSTS Preload List ,全面防御攻击
    当浏览器没有当前网站的HSTS信息,或者是第一次访问当前网站时,依然需要一次明文HTTP请求和重定向才能切换到HTTPS,以及刷新HSTS信息,而这一瞬间可能给攻击者留下可乘之机。针对此安全隐患,HSTS也有应对办法。那就是在浏览器里内置一个列表,只要是在这个列表里的域名,无论何时、何种情况,浏览器都只使用HTTPS发起连接。这个列表由Google Chromium维护,FireFox、Safari、Internet Explorer等主流浏览器均在使用。

HSTS工作原理

其工作原理主要是通过服务器,发送响应头的方式来控制浏览器操作:

  • 客户端(如:浏览器)通过HTTPS发出请求时,服务器会在返回的HTTP响应头中包含Strict-Transport-Security字段。
  • 浏览器接收到这样的信息之后,在一定期限内,对当前域名下的任何请求都只能以HTTPS发起访问请求,而不会以HTTP发起再由服务器重定向到HTTPS。

详细的工作流程图如下所示:
HSTS工作流程图

注意:更多有关max-age参数的有效期问题,参阅本文下方更多信息章节。

如何配置HSTS

你可以根据自身实际情况,选择在哪里设置HSTS,例如:反向代理服务器、应用服务器、应用程序框架,以及应用程序中自定义Header 。常见的是在NginxApacheIIS下的配置文件中配置。

  • Nginx服务器中添加下列指令进行配置:

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

    注意:在生产环境下使用HSTS机制时,建议先将max-age参数的值设置小一些(如:若干分钟),检查HSTS是否能正常工作,网站能否正常访问,然后再逐步将时间延长(如:一周/一个月),并在这个时间范围内继续检查HSTS是否正常工作,最后才改到一年。这是因为当网站证书有问题时,一旦浏览器接收到HSTS Header ,那么用户将在有HSTS效期间内,直到证书错误被修复,或者用户主动清除浏览器缓存为止,都无法访问到你的网站。

  • Apache下的配置:

    1. httpd.conf文件中加载headers模块:
      LoadModule headers_module /usr/lib/apache2/modules/mod_headers.so
      
    2. VirtualHost 0.0.0.0:443中添加下面代码行:
      Header always set Strict-Transport-Security "max-age=63072000; includeSubdomains; preload"
      
    3. 重启Apache服务器。
  • IIS下的配置:
    web.config文件中添加下列命令行进行配置:

    <?xml version="1.0" encoding="UTF-8"?>
    <configuration>
    <system.webServer>
        <rewrite>
            <rules>
                <rule name="HTTP to HTTPS redirect" stopProcessing="true">
                    <match url="(.*)" />
                    <conditions>
                        <add input="{HTTPS}" pattern="off" ignoreCase="true" />
                    </conditions>
                    <action type="Redirect" url="https://{HTTP_HOST}/{R:1}"
                        redirectType="Permanent" />
                </rule>
            </rules>
            <outboundRules>
                <rule name="Add Strict-Transport-Security when HTTPS" enabled="true">
                    <match serverVariable="RESPONSE_Strict_Transport_Security"
                        pattern=".*" />
                    <conditions>
                        <add input="{HTTPS}" pattern="on" ignoreCase="true" />
                    </conditions>
                    <action type="Rewrite" value="max-age=31536000" />
                </rule>
            </outboundRules>
        </rewrite>
    </system.webServer>
    </configuration>
    

更多信息

Max-age参数有效期如何计算,到期后怎么办?

因为HSTS Header存在于每个响应中,随着用户和网站的交互,这个有效时间时刻都在刷新。再加上有效期通常都被设置成一年,所以只要用户的前后两次请求之间的时间间隔没有超过一年,则基本上不会出现安全风险。更何况,就算超过了有效期,但是只要用户和网站再进行一次新的交互,用户的浏览器又将开启有效期为一年的HSTS保护。

如何申请将域名添加到浏览器内置列表中?

当你的网站满足以下条件后,可以在HSTS Preload List 官网上提交申请:

  • 拥有一个有效的证书
  • 在同一台主机上提供重定向响应,且接收重定向过来的HTTPS请求
  • 所有子域名均使用HTTPS
  • 在根域名的HTTP响应头中,加入HSTS Header,并满足:
    • 有效期不得少于18周(10886400秒)
    • 必须包含includeSubDomains参数
    • 必须包含preload参数

如何查询域名已经成功加入到浏览器内置列表中?

从提交申请到完成审核,成功加入到内置列表 ,需要等待几天到几周不等的时间。可通过官网,或者在Chrome地址栏里输入chrome://net-internals/#hsts查询状态。

支持HSTS机制的浏览器有哪些?

目前,支持HSTS的浏览器清单如下所示:

  • Google Chrome 4.0.211.0及以上版本
  • Firefox 4及以上版本
  • Opera 12及以上版本
  • Safari OS X Mavericks及以上版本
  • Internet Explorer (Windows 10 预览版)及以上版本