Getting an A+ Rating on SSL Labs
Part of managing a web server is not only ensuring your web server supports and processes requests through the HTTPS protocol, but to also use the protocol securely. Qualys SSL Labs as a perfect tool to quickly test your server for free for known vulnerabilities and gives you a rating as well as hints on what to do to harden your web server.
Knowledge Prerequisites
Before we continue, I assume you have proficient knowledge in getting around your server, finding configuration files, and restarting services. This article will be using NGINX in examples however the concepts should be easily transferrable to other web server technologies as well.
The SSL Certificate
The first thing is to ensure that you have an SSL certificate. If you already have one, then you can ignore most of this section. If you don't have one, Let's Encrypt is a non-profit free organization supported by the Linux Foundation and backed by many major sponsers that provides free SSL certificates.
Their tool allows for easy installation and can even automatically configure your webserver to use generated SSL certificates. All you need is a domain that is pointed to the server that is using Let's Encrypt, which also serves as proof of ownership of the domain.
Once you have an SSL certificate, here's a basic sample NGINX configuration:
server {
# Response to http requests...
listen 80;
listen [::]:80;
server_name example.com;
# But redirect them to the https equivilant.
return 301 https://example.com$request_uri;
}
server {
listen 0.0.0.0:443 ssl;
listen [::]:443 ssl;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_session_cache shared:SSL:5m;
ssl_session_timeout 1h;
# Other directives are omitted for brevity
}
Note config above is starting point just enough to get your webserver to use your SSL certificate. Continuing on we'll add onto this config.
SSL Protocols & Ciphers
Just adding a SSL certificate is unfortunately not enough to be secure. There are many different protocols and ciphers, some of which have known issues and are vulnerable. Therefore we should declare acceptable ciphers and SSL protocols.
Disclaimer: These list of recommended protocols and ciphers do change. This section will show you an acceptable list at the time of writing, however care and research should be taken to ensure that the displayed protocols and ciphers are still acceptable.
server {
...
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_session_cache shared:SSL:5m;
ssl_session_timeout 1h;
ssl_prefer_server_ciphers on;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
}
Diffie-Hellman Parameters
Diffie-Hellman Parameters (often referred to as DH Params) is a method of securely exchanging cryptographic keys over a public channel. We won't get into more into what it is exactly, but it is important for proper SSL configuration. Interested readers can learn more here.
First, we'll need to generate DH params. This can take awhile, so you may want to grab a cup of java.
cd /etc/ssl/certs
openssl dhparam -out dhparam.pem 4096
Lastly, back to the NGINX config:
server {
...
ssl_dhparam /etc/nginx/ssl/dhparams.pem;
}
HSTS
HTTP Strict Transport Security is a way of telling the browser that it should never load a site using HTTP protocol. Switching from HTTP to HTTPS is valid and works, but switching from HTTPS to HTTP is not valid, and the browser should automatically convert all HTTP requests to HTTPS. You can enable this with the following NGINX directive:
server {
...
add_header Strict-Transport-Security max-age=63072000;
}
HTTP/2
HTTP/2 is a high performance predecessor of the HTTP protocol, which can be enabled assuming you have followed this article thus far. It's primary goals is to reduce latency by using full request and response multiplexing and minimizing the HTTP protocol overhead. The best part is, if the browser doesn't support HTTP/2, it will automatically fallback to traditional HTTPS over HTTP/1.1
Enable HTTP2 by making the following modification to the listen
directive:
server {
listen 0.0.0.0:443 ssl http2;
listen [::]:443 ssl http2;
}
Controlling Frames
Lastly, this isn't much of a SSL thing or something SSL Labs checks, but still a good measure to add.
If you don't expect third-party to iframe your website, or you only use first-party code, consider adding a X-Frame-Options header like so:
server {
...
add_header X-Frame-Options DENY;
}
Alternatively, if you need iframes to your own origin, you can allow SAMEORIGIN
:
server {
...
add_header X-Frame-Options SAMEORIGIN;
}
By doing the above, I managed to get a great overall rating on SSL Labs while maintaing still a healthy amount of supported devices including devices as far back as Android 4.4.2
Like previously mentioned, security standards are constantly evolving. I use periodically check my website(s) using SSL Labs among paying attention to other news outlets to watch for when a TLS version may become deprecated.
About the author
Norman Breau is an IT professional with over 10 years of field experience.
He has a wide range of skill sets, ranging from web & software development &
architecture, to Server & Database administration. Presently he works at
TotalPave where he plays
a lead role in software projects as well as manages the server infrastructure.
On his own time, he volunteers to some open source projects, namely Apache Cordova, as many projects
throughout his career were dependent on the Cordova project. Open source projects works the best when there are volunteers that depend on such software is able to contribute in some form.
Additionally, he has been working on a newer project called Fuse,
a framework for building native-web hybrid mobile applications. The framework
intends to fill a void somewheres between CapacitorJS and pure native development.
Fuse is simply just a native library, with a bundleable webview JS API.
Unlike Cordova and CapacitorJS, Fuse is more tailored to native developers,
who want to still utilise the webview for their application's UI but retain
full control over the native project and native code. The only requirement
is that Fuse needs to be installed in the application along with a compatible
Fuse JS runtime. Fuse offers the webview and a bridging API that natively
supports binary and is incredibly fast.
Like all websites, web hosting costs money. If the above article has helped you, please considering offering a small tip as a token of appreciation.