December 27, 2010

There is a common pitfall when implementing HTTP Strict Transport Security on sites that 301 redirect from x.com -> http://www.x.com 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.

HSTS

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, yoursite.com 301 -> http://www.yoursite.com or http://www.yoursite.com 301 -> yoursite.com. This is fairly standard these days for SEO purposes (go to paypal.com for an example).

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 http://www.paypal.com. 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 paypal.com. Then open Developer Tools and go to the Resources tab. You’ll see an unencrypted 301 redirect from http://paypal.com to https://www.paypal.com. The response from https://www.paypal.com will set the HSTS policy. Now open a new tab and go to http://www.paypal.com. Open Developer Tools again and you’ll see the browser goes directly to the encrypted https://www.paypal.com, HSTS in action! Now open a new tab and go to paypal.com (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 http://pixi.me. 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 http://www.paypal.com, or even http://paypal.com, 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.”

– browser stores HSTS policy for yoursite.com and will never connect to it without encryption for a month
– browser requests https://www.yoursite.com
– server sets HSTS header and serves up standard homepage

– browser stores HSTS policy for http://www.yoursite.com and will never connect to it without encryption for a month

Now you have secured both users who type yoursite.com into the location bar and those who type http://www.yoursite.com. 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 http://www.yoursite.com and then a week later typed in yoursite.com. That user’s first ever connection to yoursite.com will still be open to a MITM attack.

Solution 2

To secure both yoursite.com and http://www.yoursite.com on the initial connection to either here’s what you would have to do. First make sure you have the simple 301 redirects from http://yoursite.com or https://yoursite.com to https://www.yoursite.com as most sites already have done. Then embed an invisible iframe on the landing page (or every page) of https://www.yoursite.com which loads https://yoursite.com/hsts. 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 yoursite.com.

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 site.com -> http://www.site.com 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 http://www.site.com -> site.com canonical redirects. But even that isn’t perfect because it would also enforce the HSTS policy on other possibly unimportant subdomains like blog.site.com.

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.

Maybe cache https://x.com 301 -> https://www.x.com. 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.

Another solution is to have the www site include an HTTPS reference from paypal.com, 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.

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.

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=”https://site.com/hsts.gif”, but site.com will be configured to redirect to https://www.site.com and the img load will fail and STS not be set.

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 https://www.yoursite.com/ 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.

[…] 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 […]

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

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

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 https://pixi.me/ 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!

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.