Optimize SSL/TLS for Maximum Security and Speed
Recently we changed our corporate website into a “HTTPS only” version. Most of the content is not secret information, still we have some sensitive areas. The ordering section and downloads, and additional our portal. While some areas were already covered with a lock, we felt it was time to make the jump to cover it all.
Additionally, we believe that we doing everything we can on our website, practicing security hardening ourselves. So that includes buying a SSL certificate, configure our web servers and finally tune it. In this article we share what we learned while doing so.
Nginx Configuration
For the purpose of demonstration, we will show some snippets in this article. While most of it is focused on nginx, the general rules can be applied to others like Apache. In any case, don’t simply copy snippets, but test them carefully and understand what they are doing.
Let’s start hardening and tuning!
Disable old protocols
SSL version 2 and 3 are insecure. Several weaknesses in the last years showed that you should no longer use these. Also for companies who need to be PCI DSS compliant, are enforced to remove support for SSLv3.
# Only allow TLS
ssl_protocols TLSv1.2 TLSv1.3;
Select right ciphers
Ciphers are part of the full conversation, deciding how the connection is initiated and maintained, but also how data is encrypted and protected.
Selecting the right ciphers is not easy. All kind of vulnerabilities showed that selecting a wrong cipher can weaken your security defenses. Instead, use the great page of Mozilla, which helps you selecting the right cipher set, tuned to modern browsers.
# Use specific ciphers and let client decide
ssl_ciphers 'long string of ciphers';
ssl_prefer_server_ciphers off;
New HTTPS features
Last years several new concepts have been introduced, to make the web a safer place.
Forward secrecy
The easy explanation for this feature: ensure that in the event of a private key is exposed previous recorded messages can not be decrypted. The more technical background is that no additional keys can be gathered, when another key is compromised.
OCSP stapling
Instead of just relying on clients checking for a revocation list, we can help saving a lot of bandwidth with OCSP stapling. The server will do the checking instead and stamp it with a recent check. This way the client knows the certificate is still valid.
HTST
HTST, or HTTP Strict Transport Security, helps the browser to save a preferred protocol (HTTPS). This means that after a redirect from HTTP to HTTPS, the browser next time remembers to go directly to HTTPS. This helps with ensuring the right protocol is used while limiting unneeded redirects at the same time.
# Redirect other domains, including www.domain.com
server {
listen 80;
index index.html index.htm;
server_name *.domain.com *.other-domain.com;
add_header "Cache-Control" "public, max-age=31536000";
return 301 https://domain.com;
}
See also the article HTST.
Public Key Pinning
HTTP Public Key Pinning, or HPKP is a way to glue a hostname and a public key (of the certificate). This is done at the level of the browser, which has static lists.
Performance
Every second counts on the web. So where possible, allow clients to cache data and do compression.
Compression
First level of performance tuning is sending less data on the line, with the help of file compression. For this the common used gzip module is used, which all modern browsers understand as well.
So we enable gzip, define what gets compressed, how much and how much buffering we use.
# Turn on gzip
gzip on;
# Also zip proxied requests
gzip_proxied any;
# Compression level, only do zipping if minimum length is 1100 bytes
gzip_comp_level 6;
gzip_min_length 1100;
gzip_buffers 16 8k;
# Define gzip for specific types (we don't zip fonts)
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
# Enabled (insert Vary: Accept-Encoding header)
gzip_vary on;
Caching
While compression is great, it is even better if we limit the amount of requests to our server. We want after all security AND performance.
While browsers are already smart in knowing which files have been changed, it still sends out requests.
The orange triangles show that requests have been done and returned with a 304 (not modified). The green circle is a successful 200 response (Ok) of the main test page.
So we want to reduce the amount of requests to a bare minimum. So we picked an expire date of 1 week. Long enough for normal users which return on a regular basis, while not caching entries too long. After all, when releasing new content, we want to push that to the client.
location ~* \.(?:css|js) {
root /data/website/;
expires 1w;
add_header Cache-Control public;
add_header Vary Accept-Encoding;
access_log off;
}
This configuration sets both an encoding (for compression) and sets caching to 1 week. That means that only once a week a new copy of the file is retrieved, unless the user forces a new download (CTRL+F5). Since we don’t care about logging the request of CSS and Javascript files, we don’t log it. Another slight performance win in that area as well.
HTTPS tuning
When it comes to HTTPS, a slow connection is usually caused due to the slow handshake. The main reason is network latency, in combination with the amount of packets needed to finish the handshake. The more packets, the longer it takes. The HTTP/2 protocol can help
Enable HTTP/2
Enabling HTTP/2 is easy, just add it to the listen statement. Note, you need a recent version of nginx.
listen 443 http2;
listen [::]:443 default ipv6only=on http2;
Conclusion
After all this tuning, we can learn a few things:
SSL versus TLS
SSL is old and insecure. Therefore version 2 and 3 should be disabled. TLS is fine, with TLSv1.1 and TLSv1.2 being preferred. TLSv1 might be still needed, for older browsers or some tooling (e.g. some versions of wget).
Use HTTP2
Make use of the HTTP/2 protocol to enhance the speed of HTTPS connections.
Security AND Performance
Instead of security battling against performance, the combination is possible.
- Test your SSL configuration SSL Labs.
- Use the Gzip module for nginx
- Use website speed testing tools like Pingdom tools to determine any bottlenecks.
Other resources
Chrome
Internal link for Chrome to check HTST database: chrome://net-internals/#htst