Here is a guide for enabling Public Key Pinning Support Nginx Ubuntu Cloud Server, which is essentially an advanced step for HSTS setup. We have discussed about HSTS for Nginx, Online Certificate Status Protocol (OSCP) and OCSP stapling and this article on Public Key Pinning is one level up.
Public Key Pinning Support Nginx Ubuntu Cloud Server : Basics
Public Key Pinning Extension for HTTP is described here by Google Inc. (October 5, 2014) as draft at the time of publication of this article :
1 | https://tools.ietf.org/html/draft-ietf-websec-key-pinning-21 |
As written on the draft as an abstract – a new HTTP header that allows web host operators to instruct user agents to remember (“pin”) the hosts’ cryptographic identities over a period of time. During that time, UAs will require that the host presents a certificate chain including at least one Subject Public Key Info structure whose fingerprint matches one of the pinned fingerprints for that host. By effectively reducing the number of trusted authorities who can authenticate the domain during the lifetime of the pin, pinning may reduce the incidence of man-in-the-middle attacks due to compromised Certification Authorities.
---
This is important for possible vulnerabilities added for running Governmental Spyware activities. Certification Authorities will be the next target of NSA for sure. It is very important for Cloud Servers as they are multi tenant in nature. nginx with NAXSI is too secure to hack, yet, if the HSTS is compromised via compromised Certification Authorities, our servers will be too tweak for the port 80.
Public Key Pinning Support Nginx Ubuntu Cloud Server : Steps
What we do to check return of a HSTS domain? we run cURL with grep :
1 | curl -I -s https://thecustomizewindows.com | grep "Strict" |
We will get the output :
1 | Strict-Transport-Security: max-age=31536000; includeSubDomains; preload |
Now run this :
1 | curl -I -s https://raymii.org | grep "Public-Key-Pins" |
We will get the output :
1 | Public-Key-Pins: pin-sha256="klO23nT2ehFDXCfx3eHTDRESMz3asj1muO+4aIdjiuY="; pin-sha256="633lt352PKRXbOwf4xSEa1M517scpD3l5f79xMD9r9Q="; max-age=2592000; includeSubDomains |
How to get it? Most importantly, how to safe guard? The safest way to pin TLS certificate™s public key is to include the pin of a second public key. This RSA key should in no way be related to your first key, just generate a new one.
In other words, we have two SSL certificates, both from GeoTrust. One is for only the bare domain and another is both for www.thecustomizewindows.com
and thecustomizewindows.com
. This is not a mistake! We have two front end servers to handle www
– only the redirections. In case our main server’s cert gets compromised, we can use the second one! We have a bash script handy to do it! You can use your real Keys in use, but it can be a point of failure and itself can backfire.
Another option is to seat and wait when we will be under attack and revoke. Revoking is not good, but re-issue is good which we said in Generate CSR, Private Key With SHA256 Signature article. The Public Key Pinning is different from the limited preload list based key pinning introduced by Firefox. Steps are simple :
1 | openssl req -inform pem -pubkey -noout < example.com.csr | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | base64 |
As usually you will not have two different SSL certs, you need to generate a csr
file and generate a “backup” pin too :
1 | openssl req -new -newkey rsa:4096 -nodes -sha256 \ -keyout example.com.backup.key -out example.com.backup.csr |
We have ready to use two sets of keys!
In case of Nginx, we will add this line in SSL server block :
1 | add_header Public-Key-Pins 'pin-sha256="base64+info1="; pin-sha256="backup+pin+here=="; max-age=15768000; includeSubDomains'; |
max-age=15768000
is 6 months. You can increase it to match with your SSL cert’s expiration time. Run nginx -t
and then service nginx restart
to test on SSL Labs.