December 27, 2010

Canonical redirect pitfalls with HTTP Strict Transport Security and some solutions

Filed under: security — Tags: — coderrr @ 4:21 pm


There is a common pitfall when implementing HTTP Strict Transport Security on sites that 301 redirect from -> which leaves your users open to a MITM attack.  Paypal is an example of one of the sites affected by this issue.  There are some solutions but none are ideal.


HTTP Strict Transport Security (HSTS) is a mechanism for websites to instruct browsers to only ever connect to them using an encrypted HTTPS connection.  It solves the problem of man in the middle attacks (MITM) (except on the browser’s first ever connection to the site) which could allow an attacker to keep the user from connecting the secure version of the site and do evil things to them.

It’s generally very simple to setup.  You just 301 redirect any HTTP connections to the HTTPS version of your site and then you add an HTTP header (Strict-Transport-Security: max-age=TTL_IN_SECONDS) to every HTTPS response.  That’s it.  Note that you cannot put the HSTS header on unencrypted HTTP responses because this would allow an attacker to expire your HSTS policy prematurely.

HSTS with Canonical Redirects

Because of that last point it gets a little trickier when dealing with a website that does canonical redirects.  A canonical redirect is just a permanent 301 redirect.  For example, 301 -> or 301 ->  This is fairly standard these days for SEO purposes (go to for an example).

Let’s say your canonical redirect is from to  So you setup the -> and -> 301 redirects and you set the HSTS header on responses.  This protects any user who goes directly to in their browser.  But most often people will type in the domain without the www.  Those users will still be open to MITM attacks as the -> redirect will always be unencrypted.  The HSTS headers on will not affect

Paypal Fail

For a real world example of this let’s check out Paypal.  They were the “first major internet site” to start using HSTS.  To be fair they are still beta testing it (with a max-age of less than 10 minutes) and mention explicitly that it’s only enabled on  Although they don’t mention the ramifications of that.

Using the latest version of Google Chrome (which is the only non beta browser that currently supports HSTS) go to  Then open Developer Tools and go to the Resources tab.  You’ll see an unencrypted 301 redirect from to  The response from will set the HSTS policy.  Now open a new tab and go to  Open Developer Tools again and you’ll see the browser goes directly to the encrypted, HSTS in action!  Now open a new tab and go to (without the www) again.  You’ll see this time Developer Tools shows there’s still an unencrypted 301 redirect, meaning an attacker can still get you with a MITM attack.  This is a perfect example of the canonical redirect pitfall with HSTS.  Another site which has the exact same problem is  My guess is this error will repeat itself many times once more sites start implementing HSTS.

This issue doesn’t seem to be readily apparent to a lot of people or at least they don’t mention it.  Even people who should probably be the most aware of it.  Here’s an except from the Security Now podcast by Steven Gibson talking about Paypal HSTS:

“So, for example, if the user put in just, or even, if there is a Strict Transport Security token that has been received previously, the browser has permission to ignore that non-secure query request from the user and to transparently make it secure.”

And after reading Paypal’s HSTS announcement you’d assume that typing in would be secure too.

Solution 1

To fix this we must set an HSTS policy on both and  Here’s how:

1) Setup a 301 redirect from to
2) Setup a 301 redirect from to
3) Set an HSTS header on the redirect (or all responses) from
4) Setup a 301 redirect from to
5) Set an HSTS header on all responses from

So the redirect chains will look like this: -> ->
OR ->

And the request response cycle will look like this (for the first redirect chain):

– browser requests
– server redirects to

HTTP/1.1 301 Moved Permanently

– browser requests
– server redirects to and sets HSTS header

HTTP/1.1 301 Moved Permanently
Strict-Transport-Security: max-age=2592000

– browser stores HSTS policy for and will never connect to it without encryption for a month
– browser requests
– server sets HSTS header and serves up standard homepage

HTTP/1.1 200 OK
Strict-Transport-Security: max-age=2592000
Content-type: text/html

– browser stores HSTS policy for and will never connect to it without encryption for a month

Now you have secured both users who type into the location bar and those who type  The downside to this is that you require two HTTPS connection which will be slower for the user and more expensive for your servers.  You’ve also still not secured the user who typed in and then a week later typed in  That user’s first ever connection to will still be open to a MITM attack.

Solution 2

To secure both and on the initial connection to either here’s what you would have to do.  First make sure you have the simple 301 redirects from or to as most sites already have done.  Then embed an invisible iframe on the landing page (or every page) of which loads  This /hsts path would do nothing other than send back a blank page with the HSTS header set.  The /hsts response could also contain cache headers (Expires and Cache-Control: public) which would make the browser not re-request it for some amount of time which is less than your HSTS policy.  This still has the issue of requiring two HTTPS connections every time a user types in

How you actually implement any of the previous concepts depends entirely on your web server and framework.  This post is just meant to get the idea out there and people aware of this potential pitfall.  See the HSTS Wikipedia article for some implementation examples of HSTS.

Considering -> canonical redirects are quite ubiquitous across the web it seems like something HSTS should deal with better.  They include an HSTS option called includeSubDomains which would handle -> canonical redirects.  But even that isn’t perfect because it would also enforce the HSTS policy on other possibly unimportant subdomains like

Solution 3: Add a Hack

I wonder if it’s worth putting an explicit exception into HSTS which allows the www subdomain to set its parent domain’s HSTS policy.  Maybe only allowing it to set or increase the TTL of the policy, and never allowing it to decrease.  I think this would make HSTS much easier to implement for the vast majority of websites.

In my next post I’ll suggest some potential additions to HSTS which could make things more simple for implementers.

Thanks to Victor Costan for reviewing this post and helping me brainstorm.


  1. PayPal are aware of the issue and have a plan to fix it soon. However, they cannot do it immediately for reasons that I’m not at liberty to disclose.

    For Chrome’s case, you can also email me and I’ll add you to the builtin HSTS list in Chrome. See

    Comment by Adam Langley — December 27, 2010 @ 4:46 pm

    • Cool, yea I figured paypal was smart enough to know that. I was more using it as an prominent example of what other people might do on accident.

      Comment by coderrr — December 27, 2010 @ 4:49 pm

  2. its funny because goes to

    Comment by matt — December 27, 2010 @ 5:26 pm

    • heh, unintended

      Comment by coderrr — December 27, 2010 @ 5:27 pm

  3. Perhaps STS should require browsers to cache previous permanent redirect for as long as STS lifetime?

    Comment by porneL — December 27, 2010 @ 7:16 pm

    • Maybe cache 301 -> That’s not a bad idea for getting rid of the double HTTPS problem. But it’s still not ideal because it requires the somewhat complex setup of solution 1. The ideal solution should require as little as possible on the part of the website owner.

      Comment by coderrr — December 27, 2010 @ 7:59 pm

  4. Another solution is to have the www site include an HTTPS reference from, so you don’t have an extra redirect, but you can still set a policy. This will be common behavior for many/most sites I expect.

    Comment by Andy Steingruebl — December 27, 2010 @ 9:54 pm

  5. Sorry, missed your solution. I wouldn’t do it with an iframe personally… and, you could do it in the background via JS if you wanted so as not to slow page-load times if you wanted. or at least put the reference near the bottom of the page. I don’t think the perf impact would be too bad.

    We decided explicitly to only allow top-down setting of policy, and even there, there is some debate.

    If you want, please do join the IETF discussions at the WebSec list or KeyAssure mailing lists. Happy to hear more thoughts on this.

    Or, email me/Jeff, our addresses are pretty easy to find.


    Comment by Andy Steingruebl — December 27, 2010 @ 10:19 pm

    • Yea I understand the issues with allowing policy settings on sub/parent domains. I just feel that the current way it works is going to lead to a lot of sites messing up and leaving themselves unprotected.

      I think if all browsers implement HSTS in a way such that _ANY_ response with an STS policy header is accepted then the resource loading trick from the parent domain will be sufficient. But if some browsers decide not to accept STS policy on failed resource loads you’ll run into issues like: img src=””, but will be configured to redirect to and the img load will fail and STS not be set.

      I’ll check those mailing lists out, thanks for your comments Andy.

      Comment by coderrr — December 27, 2010 @ 10:28 pm

  6. Let me go and re-check the spec but I believe you can set HSTS on a 301. So, even if the img load request were to generate a 301, it could still set the header.

    I haven’t tested it yet btw.

    Comment by Andy Steingruebl — December 27, 2010 @ 10:30 pm

    • Yes, an STS on a 301 definitely works, and it’s required by my ‘solution 1′.

      I was thinking though after the 301, the browsers now tries to load your HTML as an img and would fail the resource load. As long as it doens’t also fail the STS policy then its ok. I think the way the spec is worded it shouldn’t fail the STS policy but I’m not sure if all browsers would implement that correctly.

      Comment by coderrr — December 27, 2010 @ 10:32 pm

  7. Not sure how many sites set a static redirect to “/” and how many set it to “/$1″ for example in Apache mod_rewrite style and so preserve the resource request.

    Comment by Andy Steingruebl — December 27, 2010 @ 10:37 pm

    • True, I don’t know either.

      Comment by coderrr — December 27, 2010 @ 10:38 pm

  8. […] Write Code Like You Just Learned How to ProgramSo You Want to Be a Computer Programmer…Canonical redirect pitfalls with HTTP Strict Transport Security and some solutions « coderrrGive your programmers professional toolsURL Design — WarpspireHow to Hire CodersIBM i for […]

    Pingback by Links for 2010-12-30 — Business Developer Talk — December 30, 2010 @ 6:35 am

  9. hi,

    It’s Steve over at – thanks for bringing this to my attention. I have implemented your redirect suggestion and we’ll do the same for the rest of the VirtualHost directives for subdomains.

    best regards,


    Comment by steve caturan — December 30, 2010 @ 12:50 pm

    • Hey Steve,

      You guys are still missing step 3. There’s no HSTS header on your 301 redirect from to so the initial redirect from to is unencrypted every time.

      Comment by coderrr — December 30, 2010 @ 4:11 pm

      • could it be the wildcard SSL cert we use which can only be used with subdomains (www.,yourname. etc)? would regular cert resolve the MITM issue you exposed?

        please advice, thank you

        Comment by steve caturan — December 31, 2010 @ 12:57 am

  10. hi again,

    in our Apache configuration, the 1st instance of the VirtualHost container listening on port 443 is “ServerName” has a “Header set Strict-Transport-Security: max-age=250″ and a DocumentRoot with a 301 redirect to

    And then 1st instance of the VirtualHost container listening on port 80 has “ServerName” which has a DocumentRoot with a 301 redirect to

    Am I missing something here? please advice, thank you!

    Comment by steve caturan — December 31, 2010 @ 12:06 am

    • I dunno if I missed this last time or you just changed something but there’s now two things wrong.

      $ curl –head
      HTTP/1.1 301 Moved Permanently
      Date: Fri, 31 Dec 2010 00:53:17 GMT
      Server: Apache
      Content-Type: text/html; charset=iso-8859-1

      This should 301 to rather than


      $ curl –head
      HTTP/1.1 301 Moved Permanently
      Date: Fri, 31 Dec 2010 00:53:51 GMT
      Server: Apache
      Content-Type: text/html; charset=iso-8859-1

      This response should have an STS header on it.

      It’s been a while since I did stuff like this in Apache so I can’t tell you off the top of my head what you need to set.

      Comment by coderrr — December 31, 2010 @ 12:56 am

      • yep, i put it back your suggestion. I talked to my SSL cert provider – was told I would need to buy a regular cert for since the wildcard SSL will only protect subdomains including www – anyhow, thank you for pointing these issues out that really needed to be addressed, much appreciated!

        best regards,


        Comment by steve caturan — December 31, 2010 @ 1:41 am

  11. i spoke too soon, it looks like in Apache 2.2.17, Strict-Transport-Security is not set when a 301 redirect is in place from https://domain.tld/ -> https://www.domain.tld/

    However, in my wildcard SSL cert, Strict-Transport-Security becomes sticky when the same DocumentRoot is used for both VirtualHost containers listening for https://domain.tld/ and https://www.domain.tld/ – I’m going to use this method for now to compensate the issues you brougth up.

    Thank you again!

    Comment by steve caturan — December 31, 2010 @ 2:21 am

RSS feed for comments on this post. TrackBack URI

Leave a Reply

Please log in using one of these methods to post your comment: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

The Silver is the New Black Theme. Create a free website or blog at


Get every new post delivered to your Inbox.

Join 31 other followers

%d bloggers like this: