Strong HTTPS SSL/TLS Security for Web Servers
The goal of any security specialist or network administrator is to ensure strong security for network services. For the Internet, we do that by running HTTP over SSL/TLS connections (HTTPS).
Given its widespread usage, there is surprisingly little attention paid to how SSL is configured. SSL is easy to implement, but rarely does much thought go into what is actually being provided.
There are a few requirements for running a website over HTTPS:
- Certificate provided by a trusted authority. These will cost between $100 and $1000 per year, and require entity verification.
- Web server configured to listen on port 443 using your valid certificate.
- If you are running your services through a web proxy or load balancer, additional configuration will be required on them.
You want a strong and future-proof SSL configuration that is not vulnerable to any SSL protocol or encryption hacks. It must also maintain some level of backwards compatibility with older host software, but you must continually keep your software updated and configuration current as not to give the end-user a false sense of security.
All servers should routinely be audited for security problems.
Here are some strongly advised configuration policies for your public-facing web servers:
- Disable SSL Compression (mitigates the CRIME attack)
- Disable SSLv1, SSLv2, and SSLv3 protocols (susceptible to security vulnerabilities such as POODLE and FREAK)
- Setup a strong cipher suite that enable Forward Secrecy (ECDHE suites)
- Disable DHE suites as they are slower than ECDHE.
- Disable weak ciphers, such as MD5, DES, and RC4
- Enable HSTS (HTTP Strict Transport Security)
- Enable HPKP
- Enable TLS_FALLBACK_SCSV
- Enable the most current TLS protocol (TLSv1.2)
- Increase the default Diffie-Hellman (DH) cipher bit length (Protect against the LOGJAM attack)
Test your SSL connection
Using a tool called nmap you can scan for security holes and limits in software. You can use this tool to display a list of supported cipher suites with SSL connections. This gives you a very simple understanding of the type of encryption your server provides. First, install nmap to a Linux box if you do not already.
sudo yum install nmap [...]
The next step is to run the the nmap command and specify that you want a list of the cipher suites from the command. You must specify the server you want to initiate an SSL connection to. For this exercise we are using localhost, but any domain name or IP address can be used with an open 443 port.
nmap --script ssl-enum-ciphers -p 443 localhost
I have highlighted a few security concerns below.
nmap --script ssl-enum-ciphers -p 443 localhost Starting Nmap 6.40 ( http://nmap.org ) at 2015-03-17 12:52 PDT Nmap scan report for localhost (127.0.0.1) Host is up (0.00011s latency). Other addresses for localhost (not scanned): 127.0.0.1 PORT STATE SERVICE 443/tcp open https | ssl-enum-ciphers: | SSLv3: | ciphers: | TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA - strong | TLS_DHE_RSA_WITH_AES_128_CBC_SHA - strong | TLS_DHE_RSA_WITH_AES_256_CBC_SHA - strong | TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA - strong | TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA - strong | TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA - strong | TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA - strong | TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA - strong | TLS_RSA_WITH_3DES_EDE_CBC_SHA - strong | TLS_RSA_WITH_AES_128_CBC_SHA - strong | TLS_RSA_WITH_AES_256_CBC_SHA - strong | TLS_RSA_WITH_CAMELLIA_128_CBC_SHA - strong | TLS_RSA_WITH_CAMELLIA_256_CBC_SHA - strong | compressors: | NULL | TLSv1.0: | ciphers: | TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA - weak | TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA - strong | TLS_DHE_RSA_WITH_AES_128_CBC_SHA - strong | TLS_DHE_RSA_WITH_AES_256_CBC_SHA - strong | TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA - strong | TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA - strong | TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA - broken | TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 - broken | TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA - strong | TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA - strong | TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA - strong | TLS_RSA_EXPORT_WITH_DES40_CBC_SHA - weak | TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 - weak | TLS_RSA_EXPORT_WITH_RC4_40_MD5 - weak | TLS_RSA_WITH_3DES_EDE_CBC_SHA - strong | TLS_RSA_WITH_AES_128_CBC_SHA - strong | TLS_RSA_WITH_AES_256_CBC_SHA - strong | TLS_RSA_WITH_CAMELLIA_128_CBC_SHA - strong | TLS_RSA_WITH_CAMELLIA_256_CBC_SHA - strong | compressors: | NULL |_ least strength: broken Nmap done: 1 IP address (1 host up) scanned in 0.44 seconds
Notes regarding the example scan
Support for the SSLv3 protocol should be removed completely. Recent security risks such as the POODLE and FREAK attacks take advantage of weaknesses in the protocol, and all relevant browser clients support TLS as a replacement.
In the example above several weak or broken TLS ciphers are enabled and should be removed. These encryptions will give the end user a false sense of security, as the encryption themselves are breakable.
Because ECDHE ciphers are enabled, we can remove the slower DHE ciphers. Like DHE, ECDHE suites support Forward Secrecy, so we will not lose this enhanced security feature.
Only TLS version 1.0 was enabled. To get the best support and performance we should also enable the most recent versions.
OpenSSL cipher support
Your web server can't use the most secure ciphers if you don't have an up-to-date version of OpenSSL.
To view the complete list of ciphers available on your server run:
openssl ciphers
To upgrade your OpenSSL package on RHEL variants run:
sudo yum update openssl
Generate a new Diffie-Hellman group
Modern browsers have increased the minimum size to 1024-bit ciphers. You should generate a 2048-bit or 4096-bit group.
cd /etc/ssl/certs openssl dhparam -out dhparam.pem 2048
Make changes to your web server configuration
The examples here will be shown for the Nginx web server on RHEL variant machines.
The default configuration for Nginx is /etc/nginx/nginx.conf
, but your site may be defined within /etc/nginx/conf.d/
ssl_ciphers
line activates or inactivates specific encryption cipher suites Nginx will use to negatiate an encrypted channel between client and server.ssl_protocols
line defines which of the SSL protocols Nginx should have available for use.ssl_prefer_server_ciphers
is given a boolean value. A value of 'on' will help protect from BEAST attacks.
vim /etc/nginx/nginx.conf # specify the order of the ciphers that we want, and those we don't want ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH'; # enable only TLS protocols ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # help ensure that the browser uses the ciphers that we want ssl_prefer_server_ciphers on; # help ensure that the browser uses the ciphers that we want ssl_dhparam /etc/ssl/certs/dhparam.pem; # optimal session variables ssl_session_timeout 5m; ssl_session_cache shared:SSL:10m;
Reload Nginx configuration:
systemctl reload nginx
Re-check your HTTPS connection cipher list:
nmap --script ssl-enum-ciphers -p 443 localhost
Backwards-compatibility
The Mozilla group has provided a cipher list which intends to maintain a balance between security, performance, and backwards-compatibility. Use the following if you are hosting a public service/website:
vim /etc/nginx/nginx.conf
# include Mozilla list of ciphers for backwards-compatibility (IE6/WinXP)
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";