HPKP (HTTP Public Key Pinning) is an HTTP header that lets you pin an HTTPS certificate so that returning visitors only accept a chain that contains that. If an attacker gains control over a valid certificate, even if he manages to send that to your users, their browsers will refuse to load the content. It then can protect against rogue certs.
Nope, this is a terrible idea.
But first, let’s see how it works!
The header itself defines the hash of the certificate to pin and a max-age:
Public-Key-Pins: pin-sha256="base64-hash"; max-age=...
You can pin multiple certificates, this way you can provide a backup one too. This is by providing multiple
pin-sha256 parts in the header.
There is an optional
includeSubdomains option which enables the header to affect the subdomains too. In effect, you must use the same certificate in the chain for all of them, or at least one of the pinned ones.
You can add more certificates to the header at any time if you need to, but keep in mind that you need to wait the max-age to expire to be sure that no visitor have the old one. And also you need to make a more thorough testing, as a user may or may not have visited the domain with the header before.
As with other security-related headers, it can do automated reporting on violations. This works by specifying a report-uri part with an URL, and the browser will send a POST request when a violation occurs. It offers an automated way for you to know something is wrong.
If you want reporting only, use the
Public-Key-Pins-Report-Only header. This does not prevent loading, but tells the browser to send the report. At least you know something is wrong without affecting the user experience.
Which cert to pin?
Use an intermediate certificate instead of the final one. This way you can still rotate without modifying the header.
Also make sure that its validity exceeds the max-age of the header.
Problems with HPKP
Sounds great so far?
Nope, it’s actually a terrible idea and you shouldn’t use it and even regret that some browsers actually support it.
At the time of writing, only Chrome and Firefox supported it, with no signs of other vendors jumping in.
So, what are the problems with it?
First, if you ever lose the cert, you’ll prevent users from accessing your site. Depending on the max-age, this might be a catastrophic failure that could wreck your business.
Also, if an adversary gets to know the private key, you can not revoke and replace the certificate, as the users continue to expect that to be present in the chain.
The gist of the problem is that you can not really predict if you’ll need to replace the cert. If you do need, either because you lost it, someone stole it, or the CA got distrusted (hello StartCom SSL), you won’t be able to.
Sounds like a calculated risk, but business-wise it’s too great. Hardly any means can justify this.
And finally, it does not solve the first request problem, as new visitors still accept any valid certificate.
Attacks using HPKP
The problems described above are something you have control over. You chose to use the header, and you bear the consequences. But the mere existence of the standard opens ways for an attacker to hurt you.
What if someone gets access to your site and manages to insert an HTTP header?
In this attack, the adversary pins a certificate with a long max-age and forgets the key. In effect, it is a nuclear option to take a site off the Internet.
Similar to the suicide, but instead of forgetting the key, he demands ransom for it. Unless the owner of the domain pays and retrieves the pinned certificate, return users are blocked.
And even after that, the attacker still owns the keys, compromising security. And you, as the owner of the site, can do nothing about it.
I couldn’t not notice how often Scott Helme’s blog came up during my research for this article. His insightful posts on web security helped me a lot in understanding the big picture of the technologies and I can’t recommend it enough.
HPKP is an excellent example of a security feature that sounds great first, but ultimately does more harm than good. You don’t want to use it, as it brings unacceptable risks for most businesses, and even it’s optional, the support from browsers opens new types of attacks.