Update November 2017:
Google's Chrome security team has announced to remove support for HPKP by end of May 2018 in release 67 [9].
Internet Explorer, Edge and Safari never supported HPKP. So there are only Firefox and Opera left. For this reason we do not recommend to set up HPKP usage scenarios.
Deploying public key pinning safely will require operational and organizational maturity due to the risk that hosts may make themselves unavailable by pinning to a public key that becomes invalid.
HPKP is a security mechanism which allows HTTPS websites to resist impersonation by attackers using misissued or otherwise fraudulent certificates. The HTTPS web server passes a list of public key hashes a.k.a. pins to the client. The client caches the domain name to pin relation. We call this process pinning. On subsequent connections the clients verifies that the server uses one or more of those pinned public keys in its certificate chain [1].
HPKP support is documented in [8].
HPKP requires at least two pins to be sent to the client. One of the pin must be based on a public key in the servers certificate chain while the other must not. The second key which is not sent to the client is used as a backup key in case of the primary key is compromised and can be used for a regular certificate renewal. The backup private key should be stored in a safe place and the size should be chosen so that it fulfills your security requirements for the next certificate renewal.
Before you configure HPKP you have to decide whether you want to pin the root, intermediate or the leaf certificate in your certificate chain. Pinning intermediate certificates makes the renewal of leaf certificates easier. On the other hand, pinning leaf certificates is more secure, because MITM is not possible even when if the intermediate certificate authority is compromised. Additionally CAs typically don't guarantee the usage of a specific root or intermediate certificate. For most of the CAs browser have included multiple certificates. For security and stability reasons we recommend to pin the leaf certificate.
HPKP is enforced on client side by sending the HTTP response header Public-Key-Pins. All available header value properties are described in [2]. We recommend to add the header on the HTTPS virtual host using Apache expert settings (Configuration Center - Virtual Host - "Expert Settings") rather than on individual mappings to prevent inconsistent settings among them.
Example of the Apache expert setting:
Header set public-key-pins "pin-sha256=\"vwJbVK5Mh1vaO4wOEUzX9jnxalBjDnIJgh3cX5FMl9A=\"; pin-sha256=\"LeSTjTfnibfKHJmDfIGoWrE7JwFWMUy/+3Ft55sBTGs=\"; max-age=5184000"
A low value of max-age (e.g. a few seconds) can be used for testing purposes, so if something goes wrong, you can remove the header and the policy will expire very quickly. A higher value provides more security because of the TOFU security model described in section Drawbacks and Limitations. A reasonable value may be 60 days (5184000 seconds).
The following shell command generates the Subject Public Key Information (SPKI) fingerprint of a server certificate with the name airlock-test.ch configured on Airlock WAF [5]. The resulting value can be used for the pin-sha256 parameter value of the HPKP header.
openssl x509 -pubkey -in /opt/airlock/ext-apache/conf/ssl.crt/server.crt.airlock-test.ch.* | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | base64
We recommend to start a regular certificate renewal at least 1 month plus max-age (see Configuration) before the actual certificate expires.
This section describes how to renew a pinned certificate, e.g. because it is compromised or will expire soon. We assume that the leaf certificate is pinned as recommended in section Prerequisites.
There are 3 different ways to renew a certificate.
By reusing the old public/private key for the new certificate (order a new certificate based on the existing CSR), the certificate can be replaced without updating the HPKP header. This is because HPKP is based on the public key rather than the certificate.
This approach is recommended if you don't want to reuse the key of the old certificate or when the actual certificates private key is compromized. Steps to proceed:
This approach required updating the HPKP header at least max-age seconds before the current certificate expires. Otherwise some clients might be locked out. The approach should only be chosen when the backup key can not be used for the certificate renewal, e.g. because the size of the key is no longer suitable. Steps to proceed:
To verify that HPKP is working see section "How to verify Public Key Pinning (HPKP) is working" in [3].
We recommend to check the console events in Firefox after activating HPKP. Some common misconfigurations are reported there. Example:
Public-Key-Pins: The site specified a header that did not include a backup pin.
Pinning is deactivated in all major browsers if the certificate chain terminates at a user-defined trust anchor (see Drawbacks and Limitations). In Firefox this can be deactivated with the setting security.cert_pinning.process_headers_from_non_builtin_roots in the Firefox Configuration Editor (about:config).
[1] https://en.wikipedia.org/wiki/HTTP_Public_Key_Pinning
[2] https://developer.mozilla.org/en/docs/Web/Security/Public_Key_Pinning
[3] https://calomel.org/http_public_key_pinning_hpkp.html
[4] https://timtaubert.de/blog/2014/10/http-public-key-pinning-explained/
[5] https://tools.ietf.org/html/rfc7469#appendix-A
[6] https://www.ssllabs.com/ssltest/
[7] https://securityheaders.io/
[8] http://caniuse.com/#search=hpkp
[9] https://groups.google.com/a/chromium.org/forum/#!msg/blink-dev/he9tr7p3rZ8/eNMwKPmUBAAJ