IIS 10.0 版本 1709 HTTP 严格传输安全性 (HSTS) 支持

作者:Yanbing Shi

在 IIS 10.0 版本 1709 中,管理员可以选择在站点级别启用 HSTS 和 HTTP 到 HTTPS 重定向。

兼容性

版本 说明
IIS 10.0 版本 1709 本文介绍的功能是在 IIS 10.0 版本 1709 中引入的
IIS 10.0 和更早版本 在 IIS 10.0 版本 1709 之前,本文中所述的功能不受支持

HTTP 严格传输安全性 (HSTS)

RFC 6797 中指定的 HTTP 严格传输安全性 (HSTS) 允许网站将自身声明为安全主机,并通知浏览器仅应通过 HTTPS 连接联系它。 HSTS 是一项选择加入的安全增强功能,可强制实施 HTTPS,并显著减少中间人类型的攻击在服务器和客户端之间截获请求和响应的能力。

HSTS 通过需要 Web 服务器和浏览器支持的策略强制使用 HTTPS。 启用了 HSTS 的 Web 主机可以包含一个特殊的 HTTP 响应头“Strict-Transport-Security”(STS),并在 HTTPS 响应中包含一个“max-age”指令,以请求浏览器使用 HTTPS 进行进一步通信。 浏览器会接收该标头,并为“max-age”指令指定的秒数记住 HSTS 策略。 在此时段内,如果用户尝试访问同一网站,但输入了 http:// 或完全省略方案,则浏览器将自动将不安全的链接切换到安全链接 (https://),并建立与服务器的 HTTPS 连接。 通过 HTTPS 接收响应后,浏览器还会阻止用户“单击”任何安全警告(例如有关服务器证书无效的警告)。 为了利用 HSTS,浏览器必须至少看到 HSTS 标头一次。 为了保护与给定域的第一个连接中的用户,HSTS 具有单独的机制来将已注册域的列表直接预加载到浏览器中。

在 IIS 10.0 版本 1709 之前启用 HSTS 的挑战

在 IIS 10.0 版本 1709 之前,在 IIS 服务器上启用 HSTS 需要复杂的配置。

针对以下示例场景,这里提供了两种在 IIS 10.0 版本 1709 之前启用 HSTS 的解决方案:Web 管理员希望为接受 HTTP 和 HTTPS 连接的域 contoso.com 启用 HSTS,并将所有 HTTP 流量重定向到 HTTPS。 此场景中的重定向本质上是不安全的,但它仍然是许多支持 HTTPS 的网站所遵循的模式。 仍然侦听 HTTP 的根本原因是,网站无法控制访问者如何尝试连接它 - 通过 HTTPS 还是普通 HTTP。 启用 HSTS 可大幅减少在浏览器在第一次成功 HTTPS 连接期间看到 STS 标头(通过直接访问或重定向)时不安全的 HTTP 到 HTTPS 重定向的数量。

解决方案 1:HTTP 重定向模块 + 自定义标头

可以使用 HTTP 重定向模块和两个单独的网站(一个用于 HTTP,另一个用于 HTTPS)实现将所有 HTTP 流量重定向到 HTTPS,以避免无限重定向循环。

<sites>
    <site name="Contoso-http" id="1" serverAutoStart="true">
        <application path="/" applicationPool="Contoso-http">
            <virtualDirectory path="/" physicalPath="C:\inetpub\Contoso-http" />
        </application>
        <bindings>
            <binding protocol="http" bindingInformation="*:80:contoso.com" />
        </bindings>
    </site>
    <site name="Contoso-https" id="2" serverAutoStart="true">
        <application path="/" applicationPool="Contoso-https">
            <virtualDirectory path="/" physicalPath="C:\inetpub\Contoso-https" />
        </application>
        <bindings>
            <binding protocol="https" bindingInformation="*:443:contoso.com" sslFlags="0" />
        </bindings>
    </site>
    <siteDefaults>
        <logFile logFormat="W3C" directory="%SystemDrive%\inetpub\logs\LogFiles" />
        <traceFailedRequestsLogging directory="%SystemDrive%\inetpub\logs\FailedReqLogFiles" />
    </siteDefaults>
    <applicationDefaults applicationPool="DefaultAppPool" />
    <virtualDirectoryDefaults allowSubDirConfig="true" />
</sites>

重定向规则在 HTTP 站点的 Web.config 中配置,以将所有流量路由到 HTTPS 站点,并在之后为内容服务。

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <httpRedirect enabled="true" destination="https://contoso.com" httpResponseStatus="Permanent" />
    </system.webServer>
</configuration>

通过配置 HTTPS 站点的 web.config,可以通过自定义标头添加 STS 标头。

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <httpProtocol>
            <customHeaders>
                <add name="Strict-Transport-Security" value="max-age=31536000" />
            </customHeaders>
        </httpProtocol>
    </system.webServer>
</configuration>

解决方案 2:URL 重写模块

另一种解决方案是安装 URL 重写模块,并为具有 HTTP 和 HTTPS 绑定的单个网站配置重写规则。 HTTP 到 HTTPS 重定向可由入站规则指定,同时可以通过出站规则将 STS 标头添加到 HTTPS 回复。

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

IIS 10.0 版本 1709 本机 HSTS 支持

随着 IIS 10.0 版本 1709 的发布,HSTS 现在获得了本机支持。 启用 HSTS 的配置大大简化了 - 可以通过配置每个 <site> 元素下 <hsts> 元素的特性来在站点级别启用 HSTS - 可以在网站的 HSTS 设置 <HSTS> 配置参考中找到更多详细信息。

跟随此教程,只需使用 IISAdministration PowerShell cmdlet 配置网站的 <hsts> 元素的 enabledmax-ageredirectHttpToHttps 特性即可实现此示例方案。

Import-Module IISAdministration
Reset-IISServerManager -Confirm:$false
Start-IISCommitDelay

$sitesCollection = Get-IISConfigSection -SectionPath "system.applicationHost/sites" | Get-IISConfigCollection
$siteElement = Get-IISConfigCollectionElement -ConfigCollection $sitesCollection -ConfigAttribute @{"name"="Contoso"}
$hstsElement = Get-IISConfigElement -ConfigElement $siteElement -ChildElementName "hsts"
Set-IISConfigAttributeValue -ConfigElement $hstsElement -AttributeName "enabled" -AttributeValue $true
Set-IISConfigAttributeValue -ConfigElement $hstsElement -AttributeName "max-age" -AttributeValue 31536000
Set-IISConfigAttributeValue -ConfigElement $hstsElement -AttributeName "redirectHttpToHttps" -AttributeValue $true

Stop-IISCommitDelay
Remove-Module IISAdministration

网站的 HSTS 配置如下所示:

<site name="Contoso" id="1">
    <application path="/" applicationPool="Contoso">
        <virtualDirectory path="/" physicalPath="C:\Contoso\Content" />
    </application>
    <bindings>
        <binding protocol="http" bindingInformation="*:80:contoso.com" />
        <binding protocol="https" bindingInformation="*:443:contoso.com" sslFlags="0" />
    </bindings>
    <hsts enabled="true" max-age="31536000" redirectHttpToHttps="true" />
</site>

HSTS 的本机支持还可以与 HTTP 重定向模块一起使用,从而实现更复杂的方案。

例如,网站 contoso.com 会将所有流量重定向到其子域 www.contoso.com,并且两个网站都接受 HTTP 和 HTTPS 连接。 如果网站更倾向于有单个规范地址,那么这就是一个典型方案。 建议为根域和子域启用 HSTS,因为用户可能会通过 HTTP 或 HTTPS 直接访问其中的某一个。 启用根域的 <hsts> 元素的 includeSubDomains 特性后,进一步增强了 HSTS 策略对其所有子域的覆盖范围。

<sites>
    <site name="Contoso" id="1">
        <application path="/" applicationPool="Contoso">
            <virtualDirectory path="/" physicalPath="C:\inetpub\Contoso" />
        </application>
        <bindings>
            <binding protocol="http" bindingInformation="*:80:contoso.com" />
            <binding protocol="https" bindingInformation="*:443:contoso.com" sslFlags="0" />
        </bindings>
        <hsts enabled="true" max-age="31536000" includeSubDomains="true" redirectHttpToHttps="true" />
    </site>
    <site name="Contoso-www" id="2">
        <application path="/" applicationPool="Contoso-www">
            <virtualDirectory path="/" physicalPath="C:\inetpub\Contoso-www" />
        </application>
        <bindings>
            <binding protocol="http" bindingInformation="*:80:www.contoso.com" />
            <binding protocol="https" bindingInformation="*:443:www.contoso.com" sslFlags="0" />
        </bindings>
        <hsts enabled="true" max-age="31536000" redirectHttpToHttps="true" />
    </site>
    <siteDefaults>
        <logFile logFormat="W3C" directory="%SystemDrive%\inetpub\logs\LogFiles" />
        <traceFailedRequestsLogging directory="%SystemDrive%\inetpub\logs\FailedReqLogFiles" />
    </siteDefaults>
    <applicationDefaults applicationPool="DefaultAppPool" />
    <virtualDirectoryDefaults allowSubDirConfig="true" />
</sites>

此外,可以通过根域站点的 web.config 中的 <httpRedirect> 元素配置从根域到子域的重定向。 使用此类配置时,首先会将到 contoso.com 的 HTTP 请求重定向到 HTTPS,然后将到同一站点的 HTTPS 请求重定向到 www.contoso.com,并在响应中添加 STS 标头。

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <httpRedirect enabled="true" destination="https://www.contoso.com" httpResponseStatus="Permanent" />
    </system.webServer>
</configuration>

上面的示例配置也适用于将流量从源站点重定向到不是源站点子域的目标站点的方案,只需对配置稍作修改,为源站点禁用 includeSubDomains