OPINION - Dangerous Web Security Features
This page was originally created on and last edited on .
Note this post was written in 2015. Some of the security landscape has changed since then. Read this in mind of that, and I give an update at the bottom of this post. I still think the post is useful which is why I am leaving it up, but I do advise when reading blog posts on the web to check the publication date! My publication dates are at the top and bottom of the articles.
There has been a welcome growth in a number of security options available to web site owners to protect their websites and their users. Some of these have been around for a while and some have been talked about for a while but are only starting to be supported by web browsers. Innovations like Strict-Transport-Security (aka HSTS), Public-Key-Pins (aka HPKP) and Content Security Policy (aka CSP) are being supported by more and more browsers and are now available as security options to those website owners who wish to implement them.
When Google announced they were Rolling out Public Key Pinning with HPKP Reporting there was a bit of excitement amongst the web security community on the Internet. Scott Helme also has done some fantastic work in this field, from his blog to creating a HPKP and CSP toolset, and of course the report-uri tool itself. The SSLLabs scanning tool is now showing whether sites are preloaded for HSTS, which again will spark interest in that.
So support is up, implementation is easier thanks to the work of others, and everyone should rush in, right?
Well, I want to advise caution, and think most website owners should not implement some of these, due to the risks they are putting their website under. I'm not sure that some of these options are for the mainstream, or ever should be.
So you don't think web security's important then?
That's incorrect, I absolutely do think web security is massively important. So much so I set up this site, in part to try to promote web security and improve websites! However what I don't believe is that you should set up security above all else. Implementing security, like most things in life is a balance, and you need to weigh up the risks versus the reward. My issue with implementing some of these features is that the risk they are trying to mitigate, are often much smaller than the risk they are introducing.
Why are these features so "dangerous" then?
I've a few concerns. One of the main issues with some of these feature is that they are not easily reversible if you make a mistake with them. A lot of these have long life, or even permanent status once you switch them on, and that doesn't sit comfortably with me. Yes you can argue that whoever is implementing them has a duty to make sure they are implemented properly and I don't dispute that - but people do make mistakes, and when such a mistake can basically permanently take down a website, then that should be a big cause for concern.
Even if policies are implemented properly - things do change! Websites evolve, certificates need replacing, and people who may have set up these policies will be replaced by people who don't understand them. So while you may implement all of these features, and make one of the most secure websites in the world, and pat yourself on the back for that, you may well have left a ticking time bomb for the person coming after you. When a change needs to happen that breaks these policies, all that back patting earlier may not seem worth it after all!
The other issue is that browser support is just not there yet. There have been some great strides on these recently, but there are still some missing key features from most browsers, and until they are there, there are a lot of unknowns out there and some of the bugs make some of these options downright dangerous in my opinion.
Let's get into specifics
OK let's talk about each of these options and what specifically I don't like about them:
Strict-Transport-Security or HSTS, allows you to enforce HTTPS across your site. This is good as most (if not all) websites should be using HTTPS. This prevents MITM attacks, downgrade attacks, sending plain text cookies and session ids, and also gives a small performance boost as you don't need to go to a site via a redirect if you use the non-protocol version (e.g. if you type www.tunetheweb.com into your browser rather than https://www.tunetheweb.com).
HSTS also allows you to specify a max-age of the policy, which is recommended to be long into the future - typically a year or two, whether it applies to sub-domains, and you can easily pre-load this into most common browsers. And these three things are what cause the big risks.
Specifying a max-age allows web browsers to cache the fact that a site uses HSTS. This means even if you try to visit the HTTP version, the browser will automatically convert that to HTTPS for you, before it even sends the message to the web server. This is a great security feature, and means if you ever connect to a network that attempts to listen in, or reroute your traffic, it is not able to keep you on HTTP as you were never on it. This makes attacks significantly harder. However this means if you ever have a need for a HTTP call, then this will potentially not work for some visitors who have cached the policy, until the max-age expires. With a 2 year expiry (or perhaps even longer), that basically means you have said goodbye to HTTP forever. So you had better be pretty sure that your website is indeed all HTTPS before you turn this on! And, while I'm a big fan of HTTPS and would encourage it's use pretty much everywhere, there sometimes there are good reasons to have HTTP calls (e.g. if you want to set up a HPKP reporting service using the same domain or a subdomain - see includeSubDomains next - you cannot use HTTPS). Yes there are ways around this (use another domain basically), and you can reduce the max-age time if you want to phase out this policy, but you've no guarantee that all your visitors will visit so until the max-age time is reached you are not sure all your visitors HTTP calls your your site until the original max-age expires.
The includeSubDomains option is there to add additional protection. It's sometimes possible for sibling domains, or subdomains, to get or set cookies for the other domain, which can present a security risk particularly when accessed over HTTP. By setting the includeSubDomains, you reduce that risk. However that means every subdomain better be HTTPS. If you've a sub-site that you never got round to securing (e.g. http://blog.example.com), then you've just forced yourself to upgrade with this policy. Sound far-fetched? There are examples of includeSubDomains causing issues already. Similarly companies that use the external website domain name, as their internal domain as well for internal servers, can easily DoS any internal HTTP only web-servers (e.g. intranet.example.com) by including this policy on their external website top level domain (which is easy to do inadvertently with most web servers by only having one vhost without realising the impact of this).
And then we come to the most dangerous item, because you have least control over it: preloading HSTS right into the browser. You can submit your website to a list of sites that the browser knows uses HSTS. This means the policy is preloaded, which helps protect the first visit to the site, which would not normally be protected until each visitor had successfully connected to the site and downloaded the policy for the first time. The problem with this (along with the fact that it demands includeSubDomains and a long expiry) is that there is no, real way to undo this. From Chrome preload site:
Be aware that inclusion in the preload list cannot really be undone. You can request to be removed, but it will take months for the deleted entry to reach users with a Chrome update and we cannot make guarantees about other browser vendors. Don't request inclusion unless you're sure that you can support HTTPS for the long term.
That's a serious commitment right there. Chrome maintains a list of removal requests and it's obvious a number of sites are making mistakes with this feature. Given that Chrome takes about 12 weeks from initial build, until it's put to the public that's basically a minimum of 3 months to remove this setting from Chrome (assuming everyone auto updates). Other browsers also use this list and have given no such guarantees when (or even if!) they will be removed. Preloading is basically permanent.
Going back to the example of a company which has internal websites which are http only (e.g. http://internal.example.com) - which lots of companies have. This could easily not be picked up until you preload. Say HSTS is added to bare domain (example.com) with includeSubDomains. Then anyone who visits https://example.com will pick up this policy and break the internal http only site(s). However if you are mostly using www.example.com for your website then it's unlikely anyone will visit https://example.com and so won't ever pick up this policy. Even if people give a short url without domain (example.com/page) then it will be loaded over http and likely redirect you directly to the full domain before it goes to HTTPS (https://www.example.com/page) so you still don't pick up the policy on the bare domain. This is all well and good then as nothing will break for your http sites. However it does mean you could use HSTS for a number of months and sign off your use and think all is good. Then you submit to preload and then the policy IS picked up and all internal http only domains are broken - pretty much for at least 3 months. And the only easy fix is to suddenly upgrade all those sites to HTTPS - which is not trivial task in large firms.
I like HSTS, I think websites should use it. But it's dangerous - especially with long max-age, includeSubDomains and extra especially with preloading into browsers. As long as you understand it and build up your max-age slowly, you should be ok. But you need to be aware of it's dangers. However, on the flipside, there are attacks where these are the only defenses.
Public-Key-Pins or HPKP, allows you to enforce which certificates your domain should accept, by including a hash of the certificate in a HTTP Header. This prevents any certificate issued by a rogue or compromised CA for your domain to be able to be used. It was primarily in response to issues like DigiNotar CA cert being used to issue a wildcard cert for Google, and the feeling amongst some people that certificate revocation does not work.
So this again all sounds like a good and secure thing. The problem is that it's fairly easy to fake or intercept the policy, so again the only proper way around this is by storing the policy in the browser by setting a max-age for the policy, and this really needs to be a fairly long max-age to be any use. Like my reservations for long max-ages for HSTS mentioned above, max-ages have their downsides as it ties you in. Need to suddenly change your certificate? You may not be able to once you put this policy in.
There are ways around this. The RFC states that you have to pin two independent certs, so you always have a backup. But this introduces it's own issues: you now need to create the backup key in advance - which means it needs to be stored securely, and separately from the main key (since one of the main reasons for changing a certificate - other than at renewal - is when key is compromised). And if you switch to your backup, then you are running without a backup as even if you add a new policy you need to wait for the max-age of the old policy to expire before you can be sure no one has it cached in their browser. though you could have two backups, or three, or... you get the point.
Pinning further up the tree, or pinning a few well known CA root certs, isn't an answer either as there are often multiple paths for certificates and as these are often for older devices they might not be spotted during testing, this is especially risky to do. As your server can (and should!) specify the first intermediate cert, that's an option, but that ties you in to that intermediate (and your backup one) and there is still no guarantee that intermediate will be used if the browser think's it's cached a better one. Also who knows when a CA will decide to use a new intermediate cert for your next renewal? In fact Adam Langley has a post on this on his blog
Clients deciding that “pinning is good” have caused headaches at Google. It's also worth noting that CryptoCat has committed pinning-suicide in Chrome at at the moment due to their CA having switched intermediates between renewals. They're waiting for the release of Chrome 41 to recover.
Then we come to issues like SHA-1 sunsetting, or EV now requiring CT which require new certificates (possibly issued by a new intermediate certificate) which could upset the HPKP. Yes, if pinned at the leaf certificate, you can reuse the same key and CSR so the same HPKP policy can still be used, but that has it's own downsides too. Alternatively PIN both the leaf and first intermediate (you will still need a backup but there's nothing to state that you can't pin additional certs in your main path in addition to your backup). That's not a bad idea but the point is: it's complicated.
Ultimately HPKP is complicated, and, because it's complicated, the easiest thing to do on certificate renewal is to renew your certificate against the same key - which goes against best practice. While HPKP, is intended to add security, does it actually encourage bad security practices like creating key's in advance and reusing keys?
And finally, here's an interesting question as to whether HPKP could be used as a form of attack?
Content Security Policy or CSP, allows you to enforce what policies can be loaded on your site. This is primarily to address Cross-Site Scripting (XSS), where attackers can put a <script> tag on your webpage, which will be executed under the website and users permission and potentially give up useful information like session keys to a third party.
Again the intentions behind CSP are really positive, and I again I really can't think of a better way of doing this, but that does not mean it's without risks!
The problem is that the internet is rich and varied media channel. Webpages are not boring static pages (and sorry if it seems like this one is!) and the advent of web 2.0 has introduced user generated content which is even more difficult to predict and control (the very problem CSP attempts to address!). This makes implementing a CSP policy quite a complicated task. Yes there are tools out there that can help with this, but unless you visit every page on your site, on every browser, it's impossible to find all the resources you use for sure. The report-only version of CSP is a fantastic idea for this but needs more browser support. Also the usefulness of report-only is made practically useless due to noise - mostly due to browser plugins which are blocked (as they should be) but report back when there's nothing you can or need to do about these reports!
There is also the big issue of third party plug-ins. Websites that are fully self contained are easy enough to create a policy for (though they may require policies like unsafe-inline or unsafe-eval until you get round to refactoring your code), but those that load resources from the third party sites (e.g. Google Analytics, Social Media plug-ins or chat systems like Disqus) are going to have some of these unsafe options forced on you. More importantly 3rd party plug-ins are apt to change in future and break your site, as they often load other resources themselves. Until these plug-ins fully support CSP, and publish what you need to add to your site's policy and also commit to sticking to that, it's a real gamble implementing CSP on any site with 3rd party plug-ins.
Browser support for CSP is also not quite there yet, but worse, is the bugs that are there - it's not as simple as some browsers fully supporting this feature, and other not so ignoring it without problems. From browsers not handling a mix of live and report-only CSP headers correctly (affects Chrome and Firefox and potentially Microsoft Edge too), to Firefox not supporting hash values, but excluding unsafe-inline when they are present it's pretty much impossible to implement a robust CSP2 policy at present that won't cause issues in some browsers. Even when you do it properly, and even when you are considered web security experts, it's easy to be caught out with bad browser implementations, as seen by Troy Hunt and Scott Helme. These will improve over time and the concept of Evergreen browsers which automatically update, will hopefully mean that you don't have to wait until that stubborn percentage of old IE users drop off, but for now, it's not quite there yet (and there are some questions as to whether Microsoft Edge is truly an evergreen browser).
The impact of an incorrect CSP policy, or browser issue could vary from a "Tweet This" button not loading (no big deal), to ads not loading (hurting your income), to stylesheets not loading (basically your whole website is broken). Now, the good thing is that it should be pretty easy to fix any issue with CSP (unlike certain HSTS and HPKP problems discussed above), but that still takes effort and time.
I do think CSP is a great idea, and do think it will prove to be a good thing in future, but I just feel it's not quite there yet, and so difficult to recommend.
Most sites should only use very basic versions of these options
In my opinion, some of these options are just not well enough understood for people to seriously consider implementing them on commercial sites, and that's why I've written this anti-rallying cry, to say "Stop and proceed with caution!"
It's fantastic to give a website owner this level of control, and I am not against any of these options, if people really need them. I'm just against people implementing them without fully understanding them as potentially they are very dangerous.
Yes most of the RFCs for them, and the guides various people have put on the internet about how to set the up (my own included), call out the risks but in my opinion not strongly enough.
I also think some of these policies are simply not necessary for the vast majority of websites. For the high value targets like Google, Facebook, Internet Banking sites absolutely - they are great options for them. And you would imagine the internet giants at least would have the experience and understanding necessary to implement them correctly and handle the ongoing support they require, but for most of the rest of us that's not the case. HPKP in particular requires quite a detailed attack (a certificate issued by a CA in error, or by a compromised CA, and a DNS poisoning attack), and I've really got to ask if that is more likely than a website owner accidentally DoS-ing their own site with an incorrect implementation?
My recommendations would be for most sites to use:
- HSTS with a short time initially growing over time, and without includeSubDomains and without adding to the preload list, unless you fully understand what these mean.
- Not to use HPKP at all, except in report-only mode - which will not protect your website against a rogue certificate, but will alert you when there is one (at which point full HPKP may be an option you wish to consider).
- Similarly only to use CSP in report-only mode (for now). I do think CSP will become more useful as browser support grows, but it's just not quite there yet in my opinion.
These will add a good level of security, and visibility if there are any security attacks on the site, but without the risks of blocking your sites. They are not the most secure settings possible, and some sites will require more secure settings and will benefit from the full secure options, but those represent a very small minority in my opinion.
And if you log reports - then you need to set up some sort of process to look at them regularly. Otherwise there's really no point!
I think web security is extremely important, and it's importance will only grow in this always-on internet connected world. So with that in mind, any additional tools in a website owner's security arsenal are usually to be welcomed. However security is a complicated issue, and that means some of the answers to our security problems are complicated in themselves. It's rare to find security solutions, which are easy to implement, with no downsides. You need to decide if those downsides are worth the upside of the extra protection implementing that security feature gives you. I have real worries whether these policies do have this balance (particularly in their strictest settings).
I do recognise the in built protections some of these settings have, and it's not like these fears have not been considered. I think the report-only options are a fantastic idea - and as mentioned above, perhaps using only the report-only options may be sufficient protection in themselves as a warning system, if monitored properly. I do wish the browsers had implemented the report-only options first (HPKP is available for most browsers but the report only option has only just become supported in one browser - Chrome), and there are clearly some bugs to fix here on the CSP side when you have both report-only and blocking policies at the same time, but on the whole the concept of report-only options are fantastic. However they are very, very, very noisy for CSP (which severely dents their usefulness), but so far I've had no such issue with HPKP report-only.
Additionally the fact that incorrect HPKP policies are ignored, and two distinct pins are needed for a policy to be valid and be accepted, does make it very hard for someone to screw their site up too badly. But the problem is, not in the initial set up (which these protections help ensure doesn't cause problems), but in the ongoing maintenance. Certificates need changing frequently (usually annually) so saying only certain certificates can be used on a site, doesn't really fit well with that operating model. I mentioned above, and still believe that some of these are time bombs, that even if you know how to set them up, could easily trip up the next person who looks after your website if you ever move on. Maybe, as they become more popular, they will become a standard part of every sys admins knowledge, but in my experience a lot of security options are, unfortunately, far too niche specialities.
There are other HTTP Security Headers, which have very little downsides and should be used, and I do like Scott Helme's securityheaders.io webtool for quickly analysing your website for these. I also think Certificate Transparency might be another one of those rare security options which don't have downsides, so am a big fan of that - though I accept that it's more a way of warning you of a security problem rather than blocking them. So in some ways it's similar to some of the report-only versions of above security options - and maybe that's sufficient for most sites? And again, browser and CA support is just not there yet for Certificate Transparency, but hopefully will be soon.
Ultimately, it's up to site owners to implement site settings correctly of course, and more choice and options on adding security is usually a good thing in my opinion. So perhaps my fears here are overblown and I should stop being so negative, but I think no harm to have one blog post dedicated to calling out these risks.
Update 21st April 2019
This post was recently on Hackernews and generated some discussion, so I thought I'd better clarify a few things. First up I want to say that the post is 3 and a half years old as I write this and a lot has changed since then. I think my concerns were valid back in September 2015; some of it has become less valid since, and some has proven to be entirely correct. It's probably time to do an updated posted, but until I get time to do that, here's a smaller update of where my feelings are now:
- HSTS: The web has largely moved to HTTPS since I wrote this post. Three quarters of web traffic is now over HTTPS though it should be noted that this is weighted towards the large sites that make up proportionally more of the traffic, and just over 50% of the top million websites are HTTPS by default at the time of writing. HTTPS is the majority now, and HSTS therefore is less risky than before. However that does not mean it is completely without risk. The Chrome HSTS Removal Request list (which looks like it was stopped being maintained in August 2017), still makes depressing reading for those that turned preload on in error. And just because the public web is encrypted, doesn't mean internal intranets are. In my experience, these lag the public internet, and HTTPS is often still not the norm there. In short, use HSTS, but I'm still against preload unless you know what you are doing or are a high profile target.
- HPKP: Google announced the end of HPKP, precisely for the reasons I gave in this blog post. Even Scott Helme, who was one of it's most ardent supporters anounced he was giving up too. In the end HPKP was too dangerous, and introduced more risks than it solved for most sites. As far as I'm aware preloading pinning in code in the Chrome browser still exists for very high profile sites but, unlike HSTS, there is no easy method to add yourself to this list and you basically need to ask the Chrome developers to do this for you. HPKP was largely replaced by Certificate Transparency, which gives greater visibility to certificates issued by a domain, though unlike HPKP, it does not block so does not offer the same level of protection (or risk!). HPKP was, in hindsite, too dangerous and I'm happy to see it consigned to history.
- CSP: CSP has really taken off in the last 3 years, browser bugs have been fixed, and I would now recommend it for sites as the strongest protection against XSS. It should of course be used as a backup to protections in your code rather than a replacement, but it's a great added protection for defence in depth. Saying that it is complicated to set up right. It has been shown that between 94.68% and 99.34% of CSP policies are effectively useless! The problem is setting up a secure, and useful CSP takes considerable time, effort and a great deal of understanding of your website, and often a lot of code refactoring. That's not a reason not to do it of course, but it does explain why it's usage is not where it should be. Perhaps "dangerous" was a little strong for CSP (though I stand by that assessment for HPKP and for preloading HSTS without understanding it), but it's certainly got the potential to break sites. And when you add 3rd party assets that potential increases hugely. CSP reporting is next to useless in my opinion because of the noise and variety of browsers. I have it implemented on this site (and the sites I code for work) and I monitor the volume of CSP alerts for large increases for some reason, but there's often some obscure browser that CSP has broken that goes under the radar long enough to not be noticed through those. One thing that is really useful is to use upgrade-insecure-requests to allow ease of transition to HTTPS if you've not moved yet. Browser support is good, and yes there are risks of moving to HTTPS, but you just need to get on and do this because the web is moving that way! In summary, CSP is good, and you should use it, but takes a lot of effort to implement it correctly (though you can use some features like upgrade-insecure-requests without having to use a full blown CSP).
So, all in all, there's one security option (HSTS) I do recommend now (though still without preload), one (HPKP) I feel totally vindicated on, and one (CSP) thats somewhere in the middle - use it, but with caution that it's difficult to set up correctly. Which isn't that far away from the recommendations of my original post to be honest. CSP is probably the one that changed the most as originally I only recommended it in report-only mode but I would go further than that now - providing you have the skillset and understanding to implement it properly.
I've also had a few people commenting that this post is more dangerous than the security options I'm talking about here. I strongly refute that and suggest those people have not read this post fully. I do recommend most of these security options, but only after you understand them properly (at least in their strictest settings). I think that is much better than many random blog posts recommending switching them on, often to chase a grade on a security scanning tool, without fully explaining them - which is something I see far too often! As I said at the beginning, my issue with implementing some of these features is that the risk they are trying to mitigate, are often much smaller than the risk they are introducing. Those who practice "absolute security", without a view of the risks they are mitigating against (and introducing!) often cause problems in my opinion and then that just make people relucant to implement security options in the future.
Do you agree? Disagree? Let me know below your thoughts below.
Want to read more?
This page was originally created on and last edited on .Tweet