What is HTTP Public Key Pinning (HPKP) and how can you achieve it
Priyanka Shyam
Network Geek with a robust skill set | CCDE (Written) | CCIE | CWNA | Cisco SCOR | Cisco SD-WAN Expert | Technical Writer | Multitasker | Considerate & Empathic Communicator
Before starting the discussion on HPKP, let's first understand what is pinning?
Pinning is the process of associating a host with their expected X509 (is a standard defining the format of public key certificate) certificate or public key. Once a certificate or public key is known or seen for a host, the certificate or public key is associated or 'pinned' to the host. If more than one certificate or public key is acceptable, then the program holds a pinset .In this case, the advertised identity must match one of the elements in the pinset.
HTTP Public Key Pinning (HPKP) is a security feature that tells a web client to associate a specific cryptographic public key with a certain web server to decrease the risk of MITM (man-in-the-middle) attacks with forged certificates.
Or
The HTTP Public Key Pinning (HPKP) security header, is used to tell a client to associate a particular public key to a specific web server. This security measure helps prevent man-in-the-middle (MITM) attacks in the event that an attacker compromises a certificate authority (CA) and starts issuing forged certificates. Public Key Pinning works in the following manner:
- Upon the first visit to an HTTPS-enabled website, the client receives an HTTP header which contains information about the web server certificate’s public key.
- Upon subsequent visits, the client expects the same public key to be present in the certificate chain.
- If the previously known public key is not present, then the client should display a warning or send a report of a key mismatch.
To ensure the authenticity of a server's public key used in TLS sessions, this public key is wrapped into a X.509 certificate which is usually signed by a certificate authority (CA). Web clients such as browsers trust a lot of these CAs, which can all create certificates for arbitrary domain names. If an attacker is able to compromise a single CA, they can perform MITM attacks on various TLS connections. HPKP can circumvent this threat for the HTTPS protocol by telling the client which public key belongs to a certain web server.
With this method, the browser is able to tell if the public key from the origin server has changed and therefore avoid the risk of an attack.
Public Key Pins Directives
When enabling the HPKP on your web server (which we’ll explain how to do below), there are a few directives which need / can be defined. These include:
- pin-sha256 (Mandatory) - Uses the SHA256 hash algorithm to specify the Base64 encoded Subject Public Key Information (SPKI) fingerprint.It is possible to specify multiple pins for different public keys. Some browsers might allow other hashing algorithms than SHA-256 in the future. See below on how to extract this information out of a certificate or key file.
- max-age (Mandatory) - The amount of time (in seconds) for which the web client should recognize the server as a known pinned host or we can say that the time, in seconds, that the browser should remember that this site is only to be accessed using one of the defined keys.
- includeSubDomains (Optional) - If this optional parameter is specified, this rule applies to all of the site's subdomains as well.
- report-uri (Optional) - Provides you with the option to specify a URL for which any pin validation failures should be posted to.
Example of HPKP Header
Public-Key-Pins:
pin-sha256="cUPcTAZWKaASuYWhhneDttWpY3oBAkE3h2+soZS7sWs=";
pin-sha256="M8HztCzM3elUxkcjR2S5P4hhyBNf6lHkmjAHKhpGPWE=";
max-age=5184000; includeSubDomains;
report-uri="https://www.example.org/hpkp-report"
In this example, pin-sha256="cUPcTAZWKaASuYWhhneDttWpY3oBAkE3h2+soZS7sWs="pins the server's public key used in production. The second pin declaration pin-sha256="M8HztCzM3elUxkcjR2S5P4hhyBNf6lHkmjAHKhpGPWE=" also pins the backup key. max-age=5184000 tells the client to store this information for two months, which is a reasonable time limit according to the IETF RFC. This key pinning is also valid for all subdomains, which is told by the includeSubDomains declaration. Finally, report-uri="https://www.example.net/hpkp-report" explains where to report pin validation failures.
Now the question is why in the above example we are seeing two pin-sha256 values?
You can see that it specifies two pin-sha256 values, that is the pins of two public keys. One is the pin of any public key in your current certificate chain and the other is the pin of any public key not in your current certificate chain. The latter is a backup in case your certificate expires or has to be revoked.
It is definitely not obvious which public keys you should pin and what a good backup pin would be. The answer would be: it depends. You can pin one or all of the public keys in your certificate chain and that will work. The specification requires you to have at least two pins, so you must include the SPKI hash of another CA’s root certificate, another CA’s intermediate certificate (a different tier of your current CA would also work), or another leaf certificate. The only requirement is that this pin is not equal to the hash of any of the certificates in the current chain. The poor browser cannot tell whether you gave it a valid and useful backup pin so it will happily accept random values too.
How To Enable Public Key Pins
Depending upon which web server you are using, the process for enabling HPKP will be slightly different. However, each snippet below will ultimately render the same outcome - add the Public-Key-Pins header to your HTTP responses. The snippets required for Apache and Nginx web servers are each outlined below.
Apache
The following snippet can be added to your Apache web server’s configuration file. In order for this to work, you will need to have the mod_headers module enabled.
Header set Public-Key-Pins "pin-sha256=\"base64+primary==\"; pin-sha256=\"base64+backup==\"; max-age=5184000; includeSubDomains"
The following is an example for Apache users with the placeholders filled in.
Header set Public-Key-Pins "pin-sha256=\"jkUohjD+18XbGoc3Jz5C9uC/HDyXoo4Q42ZnxArUuIM=\"; pin-sha256=\"V6V+CG2xiEkPR91kqtQp+RndQ39way8wKP8OP3IcZoA=\"; max-age=5184000; includeSubDomains"
Nginx
The following snippet can be added to your Nginx server’s configuration file. This requires that you have the ngx_http_headers_module enabled.
add_header Public-Key-Pins 'pin-sha256="base64+primary=="; pin-sha256="base64+backup=="; max-age=5184000; includeSubDomains' always;
With the placeholders filled in, the snippet should look similar to:
add_header Public-Key-Pins 'pin-sha256="jkUohjD+18XbGoc3Jz5C9uC/HDyXoo4Q42ZnxArUuIM="; pin-sha256="V6V+CG2xiEkPR91kqtQp+RndQ39way8wKP8OP3IcZoA="; max-age=5184000; includeSubDomains' always;
Browser Support
Browser support for public key SSL pinning isn’t complete yet. According to caniuse, currently three major browsers support the use of HPKP, these include: Chrome, Firefox, and Opera.
If the browser does not support public key pinning or it is the first time the browser is accessing a particular server, then the browser will accept the certificate as long as all basic checks are passed. Therefore, there is the risk of an attack if the website visitor is not using a web client which supports HPKP.
HOW DOES PUBLIC KEY PINNING WORK?
The whole purpose of public key pinning is to detect when the public key of a certificate for a specific host has changed. That may happen when an attacker compromises a CA such that they are able to issue valid certificates for any domain. A foreign CA might also just be the attacker, think of state-owned CAs that you do not want to be able to MITM your site. Any attacker intercepting a connection from a visitor to your server with a forged certificate can only be prevented by detecting that the public key has changed.
After establishing a TLS session with the server, the browser will look up any stored pins for the given hostname and check whether any of those stored pins match any of the SPKI fingerprints, (the output of applying SHA-256 to the public key information, I have described above) in the certificate chain. The connection must be terminated immediately if pin validation fails.
A valid certificate that passed all basics checks will be accepted if the browser could not find any pins stored for the current hostname. This might happen if the site does not support public key pinning and does not send any HPKP headers at all, or if this is the first time visiting and the server has not seen the HPKP header yet in a previous visit.
Using Certificate Pinning Instead of HPKP
Another option that achieves the same end goal as public key pinning is known as certificate pinning. This method is more simple than public key pinning, however isn’t as flexible. If you run an application that rotates its certificate regularly then it may be more convenient to use public key pinning. On the other hand, if the SSL certificate for your site or application is only updated every year or two, then it may be easier to simply compare the entire certificate rather than go through the process of extracting the public key from a certificate.
Public Key Pinning - In Summar
HPKP or SSL pinning is another great addition to your web server if you are looking to increase security for both you and your visitors. Implementation is quite straightforward and there should be minimal configurations required once the header is added.
Keynote:
X.509 Certificate
In cryptography, X.509 is a standard defining the format of public key certficate. X.509 certificates are used in many Internet protocols, including TLS/SSL, which is the basis for HTTPS, the secure protocol for browsing the web.
Product Security Engineer at Informatica | CEH Master | 5x AWS, 3x Azure, GCP Certified | CSFPC | SFPC | Cyber Security | IoT | DevSecOps | Top 1% at TryHackMe
1 年Priyanka Shyam Do all browsers respect the HPKP header? Also, Do HPKP is still relevant in 2023 since Chrome removed its support as there are minimal users?