Take the 2-minute tour ×
Server Fault is a question and answer site for professional system and network administrators. It's 100% free, no registration required.

What is the best way to turn on HTTP Strict Transport Security on an IIS 7 web server?

Can I just through the GUI and add the proper HTTP response header or should I be using appcmd and if so what switches?

share|improve this question
    
A lot of this depends on how you're generating the stuff IIS is serving (for example. you can set the header in PHP or ASP.NET pages from within your application). Can you tell us more about your use case? –  voretaq7 Aug 13 '12 at 21:33

5 Answers 5

up vote 11 down vote accepted

IIS has the ability to add custom headers to responses. This would seem to be the easiest way to go about it.

According to the documentation on IIS.net you can add these headers through IIS Manager:

  • In the Connections pane, go to the site, application, or directory for which you want to set a custom HTTP header.
  • In the Home pane, double-click HTTP Response Headers.
  • In the HTTP Response Headers pane, click Add... in the Actions pane.
  • In the Add Custom HTTP Response Header dialog box, set the name and value for your custom header, and then click OK.
share|improve this answer
3  
It's also possible to do this in the Web.config, which you might prefer. I've posted the details as a new answer, as they'd be really difficult to read without the sourcecode formatting that's not available in comments. –  Owen Blacker Mar 20 '13 at 15:07
    
According to the makers of HTTP Strict Transport Security IIS Module, just adding the custom header is not compliant with the draft specification (RFC 6797). You would actually need to install this IIS Module. –  Chris Feb 25 at 19:16
    
@Chris They're (kinda) wrong. Not about the spec - they're absolutely correct there - but about the fact that there's no "simple" way to comply aside from their module: Just create 2 sites, one for SSL (with the header) and one for non-SSL (without the header). Certainly the module is a little more elegant, but it's not necessary (and not warranted at all if your site is https-only and you don't serve plain HTTP responses). –  voretaq7 Feb 25 at 19:55
1  
@Chris You should add an answer referencing that module though - free upvotes! (I wasn't aware of it's existence, and for a lot of folks it's probably an easier/better option than the custom header stuff) –  voretaq7 Feb 25 at 19:57

To supplement voretaq7's answer, you could also do this using the Web.config file — add a block as follows:

<system.webServer>
    <httpProtocol>
        <customHeaders>
            <add name="Strict-Transport-Security" value="max-age=31536000"/>
        </customHeaders>
    </httpProtocol>
</system.webServer>

Obviously, you may already have a system.webServer block in your Web.config, so add this to that, if so. We prefer handling things in the Web.config rather than the GUI, because it means the config changes can be committed to our Git repository.

If you wanted to handle the HTTP-to-SSL redirection, as Greg Askew mentioned, you might find it easier to do that with a separate website in IIS. This is how we handle requiring SSL for some client sites. That site contains only an HTTP redirect and some information-disclosure fixes, all in the Web.config:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <system.web>
    <httpRuntime requestValidationMode="2.0" enableVersionHeader="false" />
  </system.web>
  <system.webServer>
    <httpRedirect enabled="true" destination="https://www.domain.co.uk/"
      httpResponseStatus="Permanent" />
    <httpProtocol>
      <customHeaders>
        <remove name="X-Powered-By" />
      </customHeaders>
    </httpProtocol>
    <rewrite>
      <outboundRules>
        <rule name="Remove RESPONSE_Server">
          <match serverVariable="RESPONSE_Server" pattern=".+" />
          <action type="Rewrite" value="" />
        </rule>
      </outboundRules>
    </rewrite>
  </system.webServer>
</configuration>

This is our preferred solution for a couple of reasons — we can easily log redirected traffic separately (as it's in a different IIS log), it doesn't involve more code in the Global.asax.cs (we don't have any code in there, which is a little more convenient for an Umbraco site) and, importantly, it means that all the config is still held in our GIT repo.

share|improve this answer
1  
To add to Owen Blacker response, for IIS I use URLScan 3.1 and have it globally remove the SERVER from the response by setting RemoveServerHeader=1, the rest of the settings have mandated to be in each site web.config file. I prefer this to just blanking out the value. –  KeyOfJ Jan 14 at 20:50
    
URLScan is a very common solution and, I would suggest, a better one than the one I'm suggesting. But it's not always the most convenient solution :o) –  Owen Blacker Jan 16 at 13:35

I would use the example from the Wikipedia link you referenced and perform the activity in global.asax for the site. This enables redirecting the request to an https url, and then insert the header into the response.

This is due to the HSTS header must be ignored if it isn't in an https response.

protected void Application_BeginRequest()
{
    switch (Request.Url.Scheme)
    {
        case "https":
            Response.AddHeader("Strict-Transport-Security", "max-age=31536000");
            break;
        case "http":
            var path = "https://" + Request.Url.Host + Request.Url.PathAndQuery;
            Response.Status = "301 Moved Permanently";
            Response.AddHeader("Location", path);
            break;
    }
}
share|improve this answer

According to the makers of HTTP Strict Transport Security IIS Module, just adding the custom header is not compliant with the draft specification (RFC 6797).

You would actually need to install this IIS Module to turn on HSTS on IIS 7.

share|improve this answer

This seems to be a pretty fail safe way of doing this. Add this code in the Global.asax - the Application_BeginRequest event fires first in the Asp.net request lifecycle: http://msdn.microsoft.com/en-us/library/system.web.httpapplication.beginrequest(v=vs.110).aspx

Per the spec, http requests must not respond with the header - so this code only adds it for https requests. Max-age is in number of seconds, and it's usually a good idea to put a large value in here (IE - 31536000 indicates the site will run SSL only for the next 365 days)

protected void Application_BeginRequest(Object sender, EventArgs e)
{
  switch (Request.Url.Scheme)
  {
    case "https":
      Response.AddHeader("Strict-Transport-Security", "max-age=31536000");
      break;
    case "http":
      var path = "https://" + Request.Url.Host + Request.Url.PathAndQuery;
      Response.Status = "301 Moved Permanently";
      Response.AddHeader("Location", path);
      break;
  }
}
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.