sandstorm
                                
                                 sandstorm copied to clipboard
                                
                                    sandstorm copied to clipboard
                            
                            
                            
                        HTTP Strict Transport Security
Sandstorm should come with an option to turn on HTTP Strict Transport Security. Ideally, such an option should be turned on by default.
+1. Some design questions to figure out:
- What happens if a user decides to re-purpose the domain? Should we set a short-ish max-age by default so as to avoid breaking the domain if the user decides to re-use it for something else? or should we just say "https is easy these days; just get a cert to use in the interm?" Maybe we could could set max-age=cert expiration date, so as long as the user doesn't delete the cert they'll have one that's valid until the HSTS directive is also expired.
- Should we use includeSubdomains? Probably, but we may need to limit this to servers where WILDCARD_HOST=*.${BASE_URL}, as otherwise the user could be trying to use other subdomains for other things, and this could break them.
For any choices here that are generally desirable, but that we decide we can't apply uniformly due to risk of breaking people's setups, it should still be possible for administrators to turn these things on via the admin panel.
- What happens if a user decides to re-purpose the domain?
I can't imagine anyone who a) would run Sandstorm and be fine with it running HTTPS, but then b) would turn around and use it for something else and insist on not doing HTTPS. Unless they wanted to use some dumb provider that refuses to do free HTTPS on custom domains (Heroku was like this for a long time but I vaguely recall recently noticing they changed it... so I'm not sure). Even then there are well-known workarounds - putting Cloudflare in front of the domain being the most obvious one. Or just not using the problematic service because, c'mon, it's 2020 and HTTPS hasn't been optional for like a decade.
It seems pretty reasonable to me to set a max-age of 1 year and say "listen, honestly you shouldn't do this, but if you really insist on repurposing this domain into a plaintext HTTP site you'll have to run an HTTPS version for at most a year to set max-age=0 and clear the old HSTS response". We could also do this only on new installs so as to avoid breaking existing setups, and on upgrade show a notification along the lines of, "We didn't turn on HSTS to avoid breaking you, but it's probably a good idea and you should probably go do it in the admin panel now".
That includeSubdomains plan sounds reasonable to me... at least if I'm remembering right how WILDCARD_HOST works. That basically means Sandstorm will own all subdomains, right? So that should be fine. We should not set preload by default though.
I can't imagine anyone who a) would run Sandstorm and be fine with it running HTTPS, but then b) would turn around and use it for something else and insist on not doing HTTPS.
I mean, personally I use HTTPS for now, but expect the HTTPS regime to fall sometime in the next 5 years when people realize PKI is fundamentally flawed by design because it relies on trusting an incredibly large group of not really trustworthy companies. My hope is we'll come up with something different. (Though I suppose if this happens, browsers will hopefully just start ignoring HSTS anyhow?)
It makes sense to support the feature, but I can absolutely personally see a reason I'd someday remove HTTPS: I really don't want to be trusting PKI.
I think 5 years is optimistic for fixing the problems with PKI :P :/ But in any case, I think it makes sense to ignore "HTTPS stops being a thing" for the purposes of deciding what to do re: HSTS.
I think I agree that HTTPS is basically mandatory these days, and would be open to just going all-in and turning it on by default with a long (~1yr) max-age. I could also be talked into a shorter max-age, maybe 30 days, which would mean on average a user de-commissioning a Sandstorm box using Let's Encrypt would have a cert that would last them until the HSTS directive expired.
So on an unrelated problem today, HSTS has ruined my Saturday afternoon, and I figured I should document an issue here:
I am trying to fix the certificate on a web application that, like Sandstorm, has all of it's HTTPS configuration generally managed through the web interface. Problem being, the RFC requires browsers to disallow the user to override security warnings if HSTS is enabled. So it became extremely difficult to fix the issue with HSTS while HSTS was enabled, because I couldn't get to the server configuration. And in my case, as suggested here, I didn't choose to opt into HSTS, the application chose to do so itself during a software update.
I'd be kinda inclined after today's frustration to say, software should not implement HSTS by default.
Hm, what if rather than just setting a "short" max-age, we set one that was equal to the cert's expiration date? This would guarantee that the current cert could continue to be used until the HSTS directive expires.
Right now I think if you're having HTTPS problems then you're hosed as far as the UI is concerned anyway, since apparently clicking through the cert warnings doesn't make websockets work, so for sandstorm's own purposes HSTS doesn't make that any worse...
(This is part of why we added cli commands for cert management).
This edge case feels like too much of a niche to justify possible MITM attacks to me.
Click-through should work fine for Sandstorm if you're going into the admin panel to fix your cert, shouldn't it?
But yeah, I wouldn't have a problem if the HSTS directive was the same lifetime as the cert on the box. The decision to make it longer should presumably be an option though, for people who want long-lived HSTS protection.
Quoting Jacob Weisz (2021-10-23 15:45:41)
Click-through should work fine for Sandstorm if you're going into the admin panel to fix your cert, shouldn't it?
No, the whole UI uses websockets to talk to the server, so if that doesn't work then the admin panel won't either. I think @kentonv ran into this early on in that page's existence.
But yeah, I wouldn't have a problem if the HSTS directive was the same lifetime as the cert on the box. The decision to make it longer should presumably be an option though, for people who want long-lived HSTS protection.
Sounds like we have a consensus.
(This is part of why we added cli commands for cert management).
Yeah, I was kinda thinking about this too. I mean, is there any situation where you can't fix a cert problem with the CLI tools? Maybe if you have some sort of provider that's managing your Sandstorm for you, such that you don't have SSH access but have admin in the web UI? That seems pretty edge case-y and also you could just talk to your provider.
Unless anyone can think of any cases like this I would still advocate for long-lived HSTS, but honestly it's not really worth bikeshedding so if the consensus is to set it for the cert lifetime then so be it.
(One issue with that though is that it might not work how you'd expect because of clock skew... i.e., if someone's clock is a few days behind, their notion of when a cert expires will be different than the server's, so the HSTS will extend past the end of the cert lifetime. I think this isn't a problem we should really care about in practice? In normal operation the cert will be renewed anyway.)
I'm not inclined to worry about clock skew.
Re: CLI: someday I'd like to have a "sandstorm distro" and be in a situation where you can just buy a sandstorm box, rather than having to install it yourself, and so at some point I want to not rely on the ability to get to the CLI, either -- though there's a lot of other things that need to happen before that.
@ocdtrekkie, are you strongly opposed to a flat 30 day expiration? Looking at the code, it would be a lot less work than trying to plumb the cert expiration date to the http handlers in the gateway.
(fwiw, I'm inclined to favor a long-lived default as well).
I mean, I'd rather people opt into it rather than it be enabled for them, in that case.
I spoke to one of the authors of the HSTS RFC yesterday (I was really irritated), and they seemed sympathetic to the point that opting into HSTS is a decision the server operator should make, and that in my scenario, I wasn't given that choice because my software did it for me without asking.
I think @ocdtrekkie has convinced me that HSTS should not be set without the user opting in.
I find it interesting that Caddy, "the only web server to use HTTPS automatically and by default," does not also enable HSTS by default. There's even a big WARNING on their page that suggests how to enable it.
@garrison I'm guessing Caddy doesn't do that because it's more general purpose than Sandstorm. We can make a more intelligent decision here because we know a lot more about the context that folks are deploying this in. That warning also isn't just for HSTS, it's for that whole section of security headers. It's there to stop people from blindly copying and pasting to "improve their security" only to find that their webapp is totally broken.