HPKP is a deprecated web security response header, the acronym stands for HTTP Public Key Pins. It was intended to prevent a compromised or rogue certificate authority from issuing a publicly trusted, but hacker-controlled, HTTPS certificate for a website. In this scenario, the hackers would be able to decrypt any intercepted HTTPS traffic to the affected website.
Tip: Web response headers are pieces of meta-data that the server includes when responding to requests. A small subset of these is referred to as security headers, as they enable and configure various security features.
HTTPS certificate infrastructure
The certificate infrastructure on which HTTPS is built is based on a web of trust. A number of companies act as Certificate Authorities (CA) which publish one or more root certificates. A set of root certificates are included in all devices in a trust store. When a website requests an HTTPS certificate of its own from a CA, the certificate is signed by a root certificate. When your computer sees an HTTPS certificate, it checks the signature. If the certificate is signed by a root certificate it trusts, then your computer also trusts the HTTPS certificate.
Tip: A CA can also have intermediate certificates signed by the root certificate. These intermediate certificates can also be used to sign HTTPS certificates for websites.
The job of a certificate authority is to only issue a certificate when they have verified that the person requesting them is the genuine owner of the website. The idea with this structure is that if a hacker creates their own certificate for a website, it won’t be signed by a CA your computer trusts, and so you will see a warning.
What did HPKP do?
The whole certificate system relies on the trustworthiness of the certificate authorities. Originally, however, there were no protections against a CA being compromised by hackers or going rogue and choosing to incorrectly issue certificates.
HPKP was designed to be a protection against this possibility. It allows websites to specify an exclusive list of certificates that can be trusted for the website in a process called pinning. It was possible to pin the root or intermediate certificate, essentially allowing a single CA to issue certificates for the website. It was also possible to pin the certificate of the website itself, preventing even the right CA from issuing another valid certificate.
Technically it’s not the certificate itself that is pinned, but a hash of the certificate’s key. A hash is a one-way cryptographic function. This means it is possible to verify that the certificate presented to the browser by the website matches a pinned certificate, but it’s not possible to use the hash to make a valid certificate.
HPKP required at least two keys to be pinned, at least one of which must be a backup and not in the current certificate chain. This backup allows you to configure a smooth handover to a new certificate that doesn’t prevent users from being able to connect.
If the HTTPS certificate presented to the browser by the website does not match one of the pinned certificates, then the browser is required to reject it and prevent the user from bypassing the certificate error message.
Structure of HPKP
The HPKP header has three mandatory parts and two optional ones. The header must be titled “Public-Key-Pins”, next two or more certificates need to have a base64 encoded SHA256 hash pinned in the format ‘pin-sha256=”<base64 encoded hash>”’. The final mandatory part is the “max-age”, which is a count in seconds for how long the browser should apply the restrictions for.
Tip: SHA256 is the hashing algorithm used by HPKP. Base64 is a character set with 64 characters: 0-9, a-z, A-Z, and the special characters “+” and “/”. The “=” is used to pad out up to the last two characters if needed.
The optional settings are “includeSubDomains” and “report-uri”. “includeSubDomains instructs the browser to apply the HPKP protections to any subdomain of the current website for the duration of the “max-age” timer. “report-uri” is a feature that allows a website to be specified where error reports can be sent, and is designed to help identify and resolve issues.
There is a second variant of the header titled “Public-Key-Pins-Report-Only”. Everything is the same, however, if an error is found no action is taken beyond returning an error message to the browser and to the “report-uri” if one is configured. The report only variant was designed to enable full-scale testing of the header before deployment, where errors wouldn’t cause issues for users.
Issues with HPKP
HPKP was deprecated for two main reasons. There were two ways in which the header could cause serious issues for the website using it, these were named HPKP Suicide and Ransom PKP.
HPKP Suicide is an issue where the legitimate owners of the website lose access to all of the pinned keys. This could happen through accidental deletion, hacking, viruses, data corruption, or for many other reasons. Due to the complexity of implementing HPKP correctly, and especially keeping it updated during certificate rotations, it is relatively easy to make a configuration error. With HPKP however, if you get things wrong, all recent visitors to your website will be prevented from being able to access your website for the length of the “max-age” timer. The website smashingmagazine.com posted an article detailing its experience with exactly this issue, which essentially took the site offline for most visitors for four days before a fix was deployed.
Ransom PKP is a theoretical attack where a hacker gains access to a web server, then steals all trusted certificates and keys and then demands a ransom for their return. In a normal set up, you could just generate new keys and certificates and have the website back up and running in less than an hour. With HPKP enabled, however, those keys are pinned, if you can’t serve a pinned certificate to users, they won’t be able to access the website for the duration of the “max-age” timer. Depending on the configuration and if backups exist, it could be impossible to resolve this issue.
With both of these issues, new users would be able to access the website as normal, as they would never have seen the old HPKP header instructing their browser to only trust the now missing certificates. All recent visitors, however, such as regular customers and readers, would have to wait for the entire duration of the “max-age” timer.
Given the severity of these issues and the complexity of the configuration and maintenance, the use of the HPKP header was very low. Eventually, major browsers agreed to drop support for it entirely and within a couple of years, the HPKP header was universally deprecated.