I got a report of a strange redirect loop on a website I (inherited, but help) manage. The reports were only from Chrome and Firefox users and just started suddenly last week, but the code on this site hadn't changed in at least 3 years, maybe longer.
What's going on here? Well, it's a redirect loop, LOL. But what KIND of redirects?
We know about these redirects, right?
- 302 - Object Moved - Look over here at THIS URL!
- 301 - Moved Permanently - NEVER COME HERE AGAIN. Go over to THIS URL!
But there's another kind of redirect.
- 307 - Internal Redirect - Someone told me earlier to go over HERE so I'm going to go there without talking to the server. Imma redirect myself.
Note the reason for the 307! HSTS. What's that?
HSTS: Strict Transport Security
HSTS is a way to keep you from inadvertently switching AWAY from SSL once you've visited a site via HTTPS. For example, you'd hate to go to your bank via HTTPS, confirm that you're secure and go about your business only to notice that at some point you're on an insecure HTTP URL. How did THAT happen, you'd ask yourself.
But didn't we write a bunch of code back in the day to force HTTPS?
Sure, but this still required that we ask the server where to go at least once, over HTTP...and every subsequent time, user keeps going to an insecure page and then redirecting.
HSTS is a way of saying "seriously, stay on HTTPS for this amount of time (like weeks). If anyone says otherwise, do an Internal Redirect and be secure anyway."
Some websites and blogs say that to implement this in IIS7+ you should just add the CustomHeader require for HSTS like this in your web.config. This is NOT correct:
This isn't technically to spec. The problem here is that you're sending the header ALWAYS even when you're not under HTTPS.
The HSTS (RFC6797) spec says
An HTTP host declares itself an HSTS Host by issuing to UAs (User Agents) an HSTS Policy, which is represented by and conveyed via the
Strict-Transport-Security HTTP response header field over secure transport (e.g., TLS).
You shouldn't send Strict-Transport-Security over HTTP, just HTTPS. Send it when they can trust you.
Instead, redirect folks to a secure version of your canonical URL, then send Strict-Transport-Security. Here is a great answer on StackOverflow from Doug Wilson.
Note the first rule directs to a secure location from insecure one. The second one adds the HTTP header for Strict-Transport-Security. The only thing I might change would be to formally canonicalize the www. prefix versus a naked domain.
redirectType="Permanent" /> pattern=".*" />
Note also that HTTP Strict Transport Security is coming to IE and Microsoft Edge as well, so it's an important piece of technology to understand.
What was happening with my old (inherited) website? Well, someone years ago wanted to make sure a specific endpoint/page on the site was served under HTTPS, so they wrote some code to do just that. No problem, right? Turns out they also added an else that effectively forced everyone to HTTP, rather than just using the current/inherited protocol.
This was a problem when Strict-Transport-Security was turned on at the root level for the entire domain. Now folks would show up on the site and get this interaction:
- GET http://foo/web
- 301 to http://foo/web/ (canonical ending slash)
- 307 to https://foo/web/
- 301 to http://foo/web (internal else that was dumb and legacy)
- rinse, repeat
What's the lesson here? A configuration change that turned this feature on at the domain level of course affected all sub-directories and apps, including our legacy one. Our legacy app wasn't ready.
Be sure to implement HTTP Strict Transport Security (HSTS) on all your sites, but be sure to test and KNOW YOUR REDIRECTS.
Related Links
© 2015 Scott Hanselman. All rights reserved.