I use Chromium, which is like the super most beta beta of Chrome, for one reason: It lets me run Chrome ‘twice’ in separate environments. I have a reason for it, but it doesn’t matter for the purpose of this post. Neither does the reason why I was editing a subdomain I rarely use. What matters is this.
I went to http://test.ipstenu.org and I got this:
My bp must have dropped because my first thought was “Oh shit, I’ve been hacked!” and I got the cold sweats. After a rant on Twitter and a plea for test help, I determined this was only happening on Chromium, which was interested, and my friend Benny pointed me to this Chromium Issue: Issue 350912: Chrome fetches https URL even when http URL explicitly specified which sure sounded right.
Now the rest of the error was telling me that test.ipstenu.org was asking I use HTTPS (which it was not) and that the SSL Cert didn’t match that domain (which was correct, but again, there is no SSL cert for that subdomain). Weird, right? Why would it force https when I didn’t ask it to! But what if I was? As I read through the ticket, I saw that you could see the headers better at chrome://net-internals/#hsts
so I ran that and got this:
mode: STRICT sts_include_subdomains:true pkp_include_subdomains:false sts_observed:1402609861.497659 pkp_observed:1402608721.515596 domain:test.ipstenu.org pubkey_hashes: [...]
That was odd. I knew I’d set this in my .htaccess file:
Header always set Strict-Transport-Security "max-age=15768000; includeSubDomains"
But from what I’d read that was getting set only if you accessed the site via HTTPS (or anything on the page was HTTPS). After all, no other browser was acting like this, not even Beta Chrome. Still I turned it off, flushed my server cache, flushed my browser cache, and deleted the TransportSecurity files from Chrome. Now it worked. Turned it back on? Error came back.
It was here I realized “Chromium has decided that if you set HSTS, you mean that everything should be HTTPS regardless of the domain…” Well that’s just peachy! I pulled the HSTS line from .htaccess and instead tossed it into a PHP file for the subdomain(s) where I needed it:
header("Strict-Transport-Security:max-age=15768000; includeSubDomains");
Now. There are two situations particular to me that make this an epic pain in the ass:
First, I’m using WordPress multisite and I have SSL turned on for one domain. Second, I’m using WMH, which means editing my vhosts file to make this work properly is more of a hassle than it’s worth.
Really wouldn’t it make more sense to check “Is this an HTTPS page? No? Okay, skip!” But this is a (to me) departure from the logic train. As my friend James (and I) understood, the logic of HSTS was “If any aspect of the page is HTTPS, force HTTPS” Instead of that happening, if you went to, say, ‘fake.ipstenu.org’ instead of going to my about page (yes, that’s on purpose), it gave me the error. If you go to ‘https://fake.ipstenu.org’ you should get a specific warning page and then a ‘shucky darn!’ page. And yet here I saw that no matter if I picked HTTPS or HTTP, I was forced to HTTPS and that’s just silly.
Does my fix work? Of course. Am I happy? Nope! Oh, and yes, I filed a bug report with Chromium. You can read it at Issue 384069: HSTS in .htaccess forces https even when not specified
Comments
3 responses to “HSTS and Chromium”
Since you all suck and decided tweeting I was wrong was better than a nice comment, let me explain.
First, I know it was wrong to put HSTS for all requests. Not denying that. but at the same time, when I read the WebSec draft about it, I hit here:
http://tools.ietf.org/html/draft-ietf-websec-strict-transport-sec-14#section-7.2
So here are my big points:
1) Client implementations must not respect STS headers sent over non-HTTPS responses. Chromium isn’t doing this.
2) I should only enforce hsts on https. I didn’t do that.
And also we look here: http://tools.ietf.org/html/draft-ietf-websec-strict-transport-sec-14#section-8.1
Now. There WAS a warning. There should not have been. Because please note, this ONLY happened on *.ipstenu.org. I have a shared cert for the whole server called mothra.ipstenu.org, and it was picking up that cert for test.ipstenu.org, crying mis-match, and failing. It shouldn’t have. It was supposed to jump to here:
But it didn’t. It said “There’s a cert for this server which isn’t being called by this subdomain, I’ll use it.
This error DID NOT HAPPEN on any mapped domains. All mapped domains here are on the same server, same IP, same everything. slides.halfelf.org worked fine, slides.ipstenu.org (which has an htaccess redirect to halfelf) did not.
@Ipstenu (Mika Epstein): Heh. As you have discovered, implementing HSTS properly is more difficult than it appears. π
Bugs in both hosts and user-agents are to be expected, which is why you get “An HSTS Host MUST NOT include the STS header field in HTTP responses” and at the same time have “If an HTTP response is received over insecure transport, the UA MUST ignore any present STS header field(s)”.
I mean, both of those seems unnecessary, right? One or the other being true would do the job perfectly well. Host shouldn’t send it, and UA should ignore it. But the reason they’re both there is because both sides of that equation can screw it up, and either one of them being true will prevent the issue. It’s only when both sides screw it up that you run into this problem.
So, in short, only send the “Strict-Transport-Security” header when the request is HTTPS, redirect HTTP requests to HTTPS when appropriate, and don’t use “includeSubDomains” unless you really, really mean it, because UAs will take that directive quite seriously.
@Otto: Oh indeed. And it’s not like I think I was right π I know I did it wrong, but so did Chromium.
I still find it terribly weird that it only impacted the ipstenu.org sites, and not … this one. I mean, it’s on the same box, same htaccess, same IP, same certs! That’s why I’m sure this is at least a partial gaff in Chromium, though, and not just a “Oh, silly Mika” day.
Either way, if one person learns from this mistake, I done good!