HSTS and HPKP

From SME Server
Jump to navigationJump to search
Warning.png Work in Progress:
This page is a Work in Progress. The contents off this page may be in flux, please have a look at this page history the to see list of changes.


PythonIcon.png Skill level: Advanced
The instructions on this page may require deviations from standard procedures. A good understanding of linux and Koozali SME Server is recommended.


Introduction

HTTP Strict Transport Security (HSTS) and HTTP Public Key Pinning (HPKP) are two mechanisms which can increase the security of your SME Server's web server. They should be implemented with care.

HTTP Strict Transport Security (HSTS)

HTTP Strict Transport Security is a mechanism that allows your web server to tell clients, once they have first connected securely (i.e., over HTTPS), to always connect securely (i.e., to never connect via HTTP), for a specified timeframe. HSTS can protect against man-in-the-middle attacks. Wikipedia, as usual, has considerably more detail. HSTS can be enabled by creating a simple custom template fragment on your server.

Enabling HSTS

Warning.png Warning:
Only enable HSTS if you plan to permanently maintain a valid TLS certificate on your server. HSTS will prevent clients from connecting via HTTP, and from bypassing certificate errors (e.g., expired certificate, non-trusted certificate, etc.) to connect to your server.


To enable HSTS on your SME Server, you must first be using HTTPS with your web server, and should ideally have a trusted TLS certificate. See Letsencrypt for one simple and free way to obtain a certificate and keep it up-to-date. You must then create a small template fragment. To begin:

[root@e-smith ~]# mkdir -p /etc/e-smith/templates-custom/etc/httpd/conf/httpd.conf/VirtualHosts/
[root@e-smith ~]# nano -w /etc/e-smith/templates-custom/etc/httpd/conf/httpd.conf/VirtualHosts/04StrictTransportSecurity

Edit the file to contain the following lines:

### Enable HTTP Strict Transport Security, lifetime 6 months  ###
Header always add Strict-Transport-Security "max-age=15768000; includeSubDomains; preload" env=HTTPS

The value of max-age is in seconds, so the value given corresponds to 6 months. After a client has visited your server using HTTPS once, it will always use HTTPS for subsequent visits within that timeframe. You may adjust this time if you wish. Press Ctrl-X to exit, and Y to save. Then, expand the template and restart your web server:

[root@e-smith ~]# expand-template /etc/httpd/conf/httpd.conf
[root@e-smith ~]# service httpd-e-smith restart

Validating HSTS

You can analyze your security headers at https://securityheaders.io/.

HTTP Public Key Pinning (HPKP)

HTTP Public Key Pinning (HPKP) lets you specify which cryptographic identities should be accepted by clients to authenticate your web server. This is done by providing cryptographic hashes of one or more public keys as part of the response headers. As with HSTS, these are cached by the client for a specified period of time. Within that time, if the client attempts to connect, and a certificate is provided which does not match one of the specified hashes, the connection will be rejected. HPKP protects against impersonation of your website using mis-issued or otherwise fraudulent certificates. You can specify a URI to which failures can be reported, if desired. HPKP is supported by Firefox and Chrome, but not Internet Explorer.

Enabling HPKP

Warning.png Warning:
Improper configuration of HPKP may render it impossible for clients to connect to your website for a significant time. Please ensure that you have selected appropriate "pins" for your host. Consider using "report-only" mode for initial deployment


Enabling HPKP is more complicated than enabling HSTS. You must determine which public keys to pin, obtain the hashes for those keys, subscribe to a reporting service if desired, and then create a template fragment with this information.

Which Public Keys to Pin

You must pin at least two public keys when using HPKP: one that is currently being used, and a backup that isn't currently being used in production. This determination is critical--if the certificate chain served by your server does not contain at least one of the public keys that are pinned, the client's connection will fail. A full discussion of which keys to pin is outside the scope of this How-to, but there is a good deal of information on the web on this subject. See this article for one example.

Obtaining Hashes

You can extract the hash information from a private key, from a certificate signing request (CSR), or from an X509 certificate. To extract from a private key, run

openssl rsa -in my-key-file.key -outform der -pubout | openssl dgst -sha256 -binary | openssl enc -base64

To extract from a CSR, run

openssl req -in my-signing-request.csr -pubkey -noout | openssl rsa -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64

And to extract from a certificate, run

openssl x509 -in my-certificate.crt -pubkey -noout | openssl rsa -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64

The output will look like this:

[root@e-smith ~]# openssl rsa -in my-key-file.key -outform der -pubout | openssl dgst -sha256 -binary | openssl enc -base64
writing RSA key
6/l2FO9X6N4kewCM7IGsaS0ib2KIQxpsVn4k6T19/iQ=
[root@e-smith ~]# 

The string beginning "6/l2..." is the SHA256 hash of the public key associated with this private key. Save this output, and repeat for whatever other keys you want to pin.

Reporting Service

User agents (i.e., web browsers) can report failed connection attempts to a third-party reporting service, if such a service is specified in the headers. One no-cost service is provided by https://report-uri.io. After you register for their services, they will provide a unique URI which can be included in your headers.

Creating the Template Fragment

Once you've determined which keys to use, obtained hashes for them, and subscribed to a reporting service if desired, you can create the template fragment to implement HPKP.

[root@e-smith ~]# mkdir -p /etc/e-smith/templates-custom/etc/httpd/conf/httpd.conf/VirtualHosts/
[root@e-smith ~]# nano -w /etc/e-smith/templates-custom/etc/httpd/conf/httpd.conf/VirtualHosts/05PublicKeyPinning

Edit the file to contain the following lines, replacing the values for pin-sha256 with the hashes you determined above, and adding or removing pin-sha256 lines as required:

### Enable HTTP Public Key Pinning, lifetime 24 hours
Header always set Public-Key-Pins \
 "pin-sha256=\"5q8u3+ik8DtXToj8Bazgk3lptrL/loAbkb1cpG1y+vU=\"; \
 pin-sha256=\"6/l2FO9X6N4kewCM7IGsaS0ib2KIQxpsVn4k6T19/iQ=\"; \
 pin-sha256=\"57+cQbXlCRtm3+Ooigd1DrLwqZOr1AC/lrJGz7INwrA=\"; \
 max-age=86400; includeSubdomains; \
 report-uri=\"https://report-uri.io/report/reallylongnumber/reportOnly\""

As above, the max-age is given in seconds. The value used above corresponds to 24 hours. In production, a longer value should be used, probably on the order of 30-60 days. For testing, however, a small value can be helpful to avoid long-term consequences of improper pins.

You can also request that clients only report pinning failures, without refusing to connect. It may be advisable to initially deploy with this setting, and see if any issues are being reported. To do this, replace the second line of the template fragment with the following:

Header always set Public-Key-Pins-Report-Only \

Once you're finished, expand the template and restart the web server:

[root@e-smith ~]# expand-template /etc/httpd/conf/httpd.conf
[root@e-smith ~]# service httpd-e-smith restart

Validating HPKP

The tool at https://report-uri.io/home/pkp_analyse will validate that your server is serving HPKP headers, and that they are appropriate (i.e., that at least one of the hashes matches what's in your TLS certificate).