Public-Key-Pins
The HTTP Public-Key-Pins response header instructed browsers to associate specific cryptographic public key hashes with a domain, rejecting future TLS connections presenting certificates with different keys.
Legacy
HTTP Public Key Pinning (HPKP) was defined in its specification and has been deprecated. Chrome and Firefox removed HPKP support. No modern browser implements this header. Certificate Transparency (CT) replaced HPKP as a safer alternative for certificate verification. CT is now enforced by default in all major browsers without requiring any header.
Usage
Public-Key-Pins was part of the HTTP Public Key Pinning
(HPKP) mechanism. A server included one or more Base64-encoded
SHA-256 hashes of public keys from its certificate chain, along
with a max-age value specifying how long the browser
remembered the pins. On subsequent visits within the pin
lifetime, the browser verified the presented certificate chain
contained at least one pinned key. A mismatch caused the
connection to fail entirely.
The intent was to protect against misissued certificates. If a certificate authority was compromised or tricked into issuing a fraudulent certificate for a domain, pinned browsers rejected the forged certificate because its public key hash did not match any stored pin.
HPKP carried serious operational risk. A misconfigured pin,
a lost private key, or a routine certificate rotation without
updating pins locked legitimate users out of the site for the
duration of max-age. Some configurations set max-age to
months, making recovery from a mistake extremely difficult.
This risk of self-imposed denial of service was the primary
reason browsers removed support.
Directives
pin-sha256
The pin-sha256 directive contains a Base64-encoded SHA-256
hash of a certificate's Subject Public Key Info (SPKI). At
least two pin-sha256 directives are required: one matching
a key in the current certificate chain and one backup pin
for a key not yet deployed. The backup pin allows recovery
if the primary key is lost or rotated.
max-age
The max-age directive specifies the number of seconds the
browser remembers the pin set. After this period expires,
the browser accepts any valid certificate for the domain
again. Common values ranged from 5184000 (60 days) to
31536000 (one year).
includeSubDomains
The includeSubDomains directive extends the pin policy to
all subdomains of the host. Without this directive, pins
apply only to the exact hostname in the request.
report-uri
The report-uri directive specifies a URL where the
browser sends JSON violation reports when a pin validation
failure occurs. This allowed operators to detect certificate
mismatches without blocking the connection, especially when
used with the related Public-Key-Pins-Report-Only header
during testing.
Example
A server pins three public key hashes with a 60-day
lifetime. The first hash matches the current certificate's
public key, and the remaining hashes serve as backups for
planned key rotations. The includeSubDomains directive
extends the policy across all subdomains.
Public-Key-Pins: pin-sha256="WrVO/NVwDzspUoFoRGbR0vR7gEj25C/saZilznWAQlM="; pin-sha256="5kJvNEMw0KjrCAu7eXY5HZdvyCS13BbA0VJG1RSP91w="; pin-sha256="r/mIkG3eEpVdm+u/ko/cwxzOMo1bk4TyHIlByibiA5E="; max-age=5184000; includeSubDomains
A minimal configuration pins a single key along with a
backup and sets a 10-day lifetime. Shorter max-age values
reduce the risk window from misconfigured pins.
Public-Key-Pins: pin-sha256="cN0QSpPIkuwpT6iP2YjEo1bEwGpH/yiUn6yhdy+HNto="; pin-sha256="WGJkyYjx1QMdMe0UqlyOKXtydPDVrk7sl2fV+nNm1r4="; max-age=864000
Takeaway
The Public-Key-Pins header was a TLS security mechanism allowing sites to pin certificate public keys, preventing connections with unauthorized certificates. The risk of misconfiguration locking out legitimate users led browsers to remove support, and Certificate Transparency now provides certificate monitoring without the self-denial risk.
See also
- RFC 7469: Public Key Pinning Extension for HTTP (deprecated)
- Strict-Transport-Security
- Expect-CT (also deprecated)
- HTTP headers