NSA Proof Your Apache Configuration

Between Heartbleed (CVE-2014-0160) and Edward Snowden the last eleven months have created quite a stir in realm of Information Security; especially when it comes to SSL. In the wake of Heartbleed I thought I would share my Apache configuration and provide some tips on preventing Heartbleed as well as implementing anti-NSA best practices.

First things first, fix the Heartbleed bug. This should be pretty simple, just make sure your running a patched version of OpenSSL. I run jasonsnider.com on Ubuntu 13.10 so this was simple as running the latest updates.

apt-get update
apt-get upgrade

QualSys SSL Labs offers an in-depth analysis of your SSL certificate. Currently my position is that if your pulling an A or an A+ on this site then you have diligently implemented anti-NSA best practices. So head over there and enter your domain name. If you are vulnerable to Heartbleed you will fail the test with a Heartbleed warning and you will want to install the latest version of OpenSSL.

Once the Heartbleed vulnerability has been patched, you'll want harden your SSL configuration. Using a RapidSSL certificate on a server running Ubuntu 13.10 and Apache 2.4.6 I was already pulling an A-. All I really needed to do was implement Perfect Forward Secrecy (PFS) to boost my grade to an A. However, a review of the analysis showed a few other things I could improve. These improvements include mitigating BEAST, hardening HTTP Strict Transport Security (HSTS) and implementing Perfect Forward Secrecy (PFS). These are all fairly easy improvements to make; nothing more than a line or two in your server's configuration.

Mitigate BEAST

While BEAST has arguably been mitigated by major browser vendors, the server side patch is trivial, so why not implement it. BEAST is easily mitigated by simply shutting down support for SSL v2.

SSLProtocol all -SSLv2

Implement HSTS

HTTP Strict Transport Security HSTS is simply denying your server the ability to make HTTP requests. There are a few ways to do this. The first is to simply not have a virtual host running over port 80. Which would typically be any Apache configuration beginning with the likes of <VirtualHost *:80>. The second is the more SEO/user friendly approach of using mod_rewrite to redirect all insecure requests to secure requests and the third is to apply theStrict-Transport-Security header to all requests coming in over http. My approach is to start of with a mod_rewrite and then use the Strict-Transport-Security header as a fall back. Here is my HSTS Strategy for jasonsnider.com.

<VirtualHost 162.243.75.115:80>
ServerAdmin xxx@xxx.xxx
ServerName jasonsnider.com

# HTTP Strict Transport Security (HSTS) Strategy

# Force SSL using mode-rewrite
# Enable mod-rewrite
# Force http to https
RewriteEngine On
RewriteRule ^(.\*)$ https://jasonsnider.com$1 \[R=301,L\]

# If the rewirte condition fails this will kill the insecure  connection
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
</VirtualHost>

Implement PFS

Using Ubuntu >=13.10 and Apache >= 2.4 implementing perfect forward secrecy (PFS) in another trivial task. All you need to do dissallow non-compliant ciphers and force the browser to honor your cipher order.

SSLCipherSuite EECDH+ECDSA+AESGCM:EECDH+aRSA+AESGCM:EECDH+ECDSA+SHA384:EECDH+ECDSA+SHA256:EECDH+aRSA+SHA384:EECDH+aRSA+SHA256:EECDH+aRSA+RC4:EECDH:EDH+aRSA:RC4:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS
SSLHonorCipherOrder on

Putting it all Together

This is the actual configuration file for jasonsnider.com.

The configuration below is derived from multiple sources including

  • Default Apache2 Config files
  • HTML5 Boilerplate
  • Trial and Error
<VirtualHost 162.243.75.115:80>
    ServerAdmin xxx@xxx.xxx
    ServerName jasonsnider.com

    # HTTP Strict Transport Security (HSTS) Strategy

    # Force SSL using mode-rewrite
    # Enable mod-rewrite
    # Force http to https
    RewriteEngine On
    RewriteRule ^(.\*)$ https://jasonsnider.com$1 \[R=301,L\]

    # If the rewirte condition fails this will kill the insecure  connection
    Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
</VirtualHost> 

<VirtualHost 162.243.75.115:443>

    # Enable mod-rewrite
    RewriteEngine On

    # Imporve SEO by rewriting www.jasonsnider.com to jasonsnider.com
    RewriteCond %{HTTP\_HOST} ^www\\.(.+)$ \[NC\]
    RewriteRule ^(.\*)$ https://jasonsnider.com$1 \[R=301,L\]

    ServerAdmin xxx@xxx.xxx
    ServerName jasonsnider.com

    DocumentRoot /var/www/jasonsnider.com/app/webroot

    <Directory /var/www/jasonsnider.com/app/webroot>
        Options Indexes FollowSymLinks MultiViews
        AllowOverride All
    </Directory>

    ErrorLog ${APACHE\_LOG\_DIR}/error.log

    # Possible values include: debug, info, notice, warn, error, crit,
    # alert, emerg.
    LogLevel warn

    CustomLog ${APACHE\_LOG\_DIR}/ssl\_access.log combined

    Alias /doc/ "/usr/share/doc/"
    <Directory "/usr/share/doc/">
        Options Indexes MultiViews FollowSymLinks
        AllowOverride None
        Order deny,allow
        Deny from all
        Allow from 127.0.0.0/255.0.0.0 ::1/128
    </Directory>

    # SSL Engine Switch:
    # Enable/Disable SSL for this virtual host.
    SSLEngine on

        # Mitigate BEAST
        SSLProtocol all -SSLv2

        # Enable PFS
        SSLCipherSuite EECDH+ECDSA+AESGCM:EECDH+aRSA+AESGCM:EECDH+ECDSA+SHA384:EECDH+ECDSA+SHA256:EECDH+aRSA+SHA384:EECDH+aRSA+SHA256:EECDH+aRSA+RC4:EECDH:EDH+aRSA:RC4:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS  
    SSLHonorCipherOrder on

    # Point to SSL Certificates
    SSLCertificateFile    /etc/apache2/ssl/CSSL635327486032376577/ServerCertificate.cer
    SSLCertificateKeyFile /etc/apache2/ssl/jasonsnider.com.key
    SSLCACertificateFile  /etc/apache2/ssl/CSSL635327486032376577/CACertificate-1.cer

    # SSL Engine Options: \[...\]
    <FilesMatch "\\.(cgi|shtml|phtml|php)$">
        SSLOptions +StdEnvVars
    </FilesMatch>

    <Directory /usr/lib/cgi-bin>
        SSLOptions +StdEnvVars
    </Directory>

    # SSL Protocol Adjustments: \[...\]
    BrowserMatch "MSIE \[2-6\]" \\
        nokeepalive ssl-unclean-shutdown \\
        downgrade-1.0 force-response-1.0
    # MSIE 7 and newer should be able to use keepalive
    BrowserMatch "MSIE \[17-9\]" ssl-unclean-shutdown

</VirtualHost>

# vim: syntax=apache ts=4 sw=4 sts=4 sr noet

More Reading

Podcasts