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:

  1. Disable SSL Compression (mitigates the CRIME attack)
  2. Disable SSLv1, SSLv2, and SSLv3 protocols (susceptible to security vulnerabilities such as POODLE and FREAK)
  3. Setup a strong cipher suite that enable Forward Secrecy (ECDHE suites)
  4. Disable DHE suites as they are slower than ECDHE.
  5. Disable weak ciphers, such as MD5, DES, and RC4
  6. Enable HSTS (HTTP Strict Transport Security)
  7. Enable HPKP
  8. Enable TLS_FALLBACK_SCSV
  9. Enable the most current TLS protocol (TLSv1.2)
  10. 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
[...]
Loaded plugins: fastestmirror, langpacks Loading mirror speeds from cached hostfile Resolving Dependencies --> Running transaction check ---> Package nmap.x86_64 2:6.40-4.el7 will be installed --> Processing Dependency: nmap-ncat = 2:6.40-4.el7 for package: 2:nmap-6.40-4.el7.x86_64 --> Running transaction check ---> Package nmap-ncat.x86_64 2:6.40-4.el7 will be installed --> Finished Dependency Resolution Dependencies Resolved =============================================================================================================== Package Arch Version Repository Size =============================================================================================================== Installing: nmap x86_64 2:6.40-4.el7 base 3.9 M Installing for dependencies: nmap-ncat x86_64 2:6.40-4.el7 base 200 k Transaction Summary =============================================================================================================== Install 1 Package (+1 Dependent package) Total download size: 4.1 M Installed size: 17 M Is this ok [y/d/N]: y Downloading packages: (1/2): nmap-ncat-6.40-4.el7.x86_64.rpm | 200 kB 00:00:02 (2/2): nmap-6.40-4.el7.x86_64.rpm | 3.9 MB 00:00:02 --------------------------------------------------------------------------------------------------------------- Total 1.5 MB/s | 4.1 MB 00:00:02 Running transaction check Running transaction test Transaction test succeeded Running transaction Installing : 2:nmap-ncat-6.40-4.el7.x86_64 1/2 Installing : 2:nmap-6.40-4.el7.x86_64 2/2 Verifying : 2:nmap-6.40-4.el7.x86_64 1/2 Verifying : 2:nmap-ncat-6.40-4.el7.x86_64 2/2 Installed: nmap.x86_64 2:6.40-4.el7 Dependency Installed: nmap-ncat.x86_64 2:6.40-4.el7 Complete!

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";