Ensuring HTTP Strict Transport Security (HSTS) Compliance without System Modification - Powershell Automation
PLEASE NOTE: There are new features available for switching off TLS 1.0. I recommend using those instead. The scenario in this blog is still relevant for setting HSTS, but it can be accomplished without an App Gateway in the design.
On June 8, 2015, the White House Office of Management and Budget issued memorandum M-15-13, “A Policy to Require Secure Connections across Federal Websites and Web Services” (https.cio.gov). This policy requires that federal agencies make all existing websites and services accessible through a secure connection (HTTPS-only, with HTTP Strict Transport Security, HSTS) by December 31, 2016. Furthermore DHS published the DHS Binding Operational Directive 18-01, which requires all public facing websites/domains in many federal agencies to be in compliance by January 17, 2018.
It is not enough to simply close off port 80 on relevant sites to make sure all traffic goes to port 443. Each response from the server must explicitly include the `Strict-Transport-Security` header. You can read more about that on Wikipedia. This can be problematic for some systems that cannot easily be modified without breaking compliance in some other way or operating them in a configuration state that is not officially supported. One such example is ADFS systems, that may need upgrading to be in complicance.
In this blog post I discuss how to use Azure services to bring a website or service into compliance without making any modifications to the system itself. In this GitHub repository I have posted scripts to stand up the necessary services. The repository also includes a script to stand up a test environment, which is not in compliance.
For testing purposes we will use a Azure Web App as the backend test system. You can create this Web App with the command:
[ps]
.\CreateHSTSTestEnvironment.ps1 -ResourceGroupName "RESOURCE GROUP NAME" `
-WebAppName "BACKENDAPPNAME" -Location "LOCATION"
[/ps]
You can test if a specific system is in compliance using SSL Labs. After standing up the web app, you should find two problems:
- Strict Transport Security (HSTS) will be "No"
- TLS 1.0 is enabled.
If it is not possibly to modify the system itself, it is possible to mitigate the problem by front-ending the system with a proxy. The repository scripts will add an Azure Web App in front of the system and configures this web app to act as proxy. Since Web Apps currently enable TLS 1.0 (which is also a compliance violation), an Azure Application Gateway is added in front.
The final topology (including remediation) would look something like this:
The complete fix (proxy web app and App Gateway) is configured using this PowerShell script
[ps]
.\ApplyHSTSFix.ps1 -ResourceGroupName "RESOURCE GROUP NAME" -ProxyWebAppName "FRONTENDAPPNAME" `
-Location "LOCATION" -Endpoint "HOSTNAME OF ENDPOINT" `
-CertificatePath "PATH TO PFX FILE"
[/ps]
You will be prompted for a password for the certificate and then the solution should automatically run. It will take a while, since provisioning a gateway takes some time.
The steps needed to configure a Web App to act as proxy is to add an applicationHost.xdt
file in the /site
folder of the web app:
[xml]
<?xml version="1.0"?>
<configuration xmlns:xdt="https://schemas.microsoft.com/XML-Document-Transform">
<system.webServer>
<proxy xdt:Transform="InsertIfMissing" enabled="true" preserveHostHeader="false" reverseRewriteHostInResponseHeaders="false" />
</system.webServer>
</configuration>
[/xml]
We then add the following web.config
in the /site/wwwroot/
folder:
[xml]
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="Probe" stopProcessing="true">
<match url="^probe.html" />
<action type="None" />
</rule>
<rule name="Proxy" stopProcessing="true">
<match url="^/?(.*)" />
<action type="Rewrite" url="https://@@HOSTNAME@@/{R:1}" />
</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>
[/xml]
@@HOSTNAME@@
needs to be replaced with the end point hostname. The Powershell automation does that for you. As you can see this causes the Web App to forward all requests to the backend unless they hit a /probe.html
endpoint. The probe endpoint is important for the Application Gateway that we will put in front of it. The web.config
also adds the HSTS header as required. The rest of the Powershell automation stands up an Application Gateway as previously described in this blog post.
After the deployment, you should point the CNAME for your application to the DNS name of the public IP associated with the gateway. Now repeat the test and you should be in compliance for both HSTS and TLS.
And that is it. Let me know if you have questions/comments/suggestions.