HTTPS Everywhere at HasGeek.com

If you’ve been following the news lately, governments around the world have been revealed to be sniffing internet traffic passing through their territories. This includes India, whose government launched a “Central Monitoring System” this April. We believe nobody but you and us has any business knowing what you are doing on our website, so starting this week we have moved all our services to be HTTPS-only.

HTTP has always been an insecure protocol – your communications are sent back and forth in plain text, readable by anyone tapping your internet connection – but the cost of switching to HTTPS and general public apathy has left us with most sites still on HTTP. Two years ago the Firesheep plugin for Firefox enabled anyone armed with merely a web browser to steal passwords and logged-in sessions from anyone around them connected to the same wireless network. Firesheep shamed several high profile sites (Twitter, Facebook, etc) into switching to HTTPS, but had little effect on the wider web community. With this year’s revelations of your own government spying on you, in violation of your constitutional rights, we think it’s time more of us took notice and turned on encryption on our servers.

HasGeek has used HTTPS for over two years on sensitive areas of our sites such as login and sign-up forms. Starting this week, we’re extending this to use HTTPS on all our 20+ websites*. HTTP is no longer supported. Our HTTPS implementation includes Forward Secrecy and is rated A by both the Qualys SSL Labs and x509labs test suites.

If you host a website, we recommend you switch to HTTPS too. Here is how.

Setting up HTTPS/SSL on your servers

  1. Get an SSL certificate. Certificates can be expensive or cheap depending on where you get them from. We use StartSSL.com, which has a particularly enlightened pricing policy: the certificates are free; you only pay for things that require human effort, like identity verification. Once you have been verified you can issue yourself as many certificates as you please for any domain you control. This allowed us to obtain a single certificate covering all our domains, with wildcard subdomains (*.hasgeek.com, etc).

    StartCom is a relatively new Certification Authority (since 2005). While their root certificate is bundled with every major operating system and browser, including Windows XP, it is notably missing in Windows Phone 7. This means IE mobile users on WP7 will be shown a scary warning message recommending they leave your site immediately (though this can be mitigated by installing the root certificate manually on each device). We have not received a single complaint from a WP7 user in two years, and given how much of the web is broken or inaccessible from WP7, and Microsoft's decision to not upgrade WP7 devices to WP8, we believe WP7 is a lost cause anyway and not worth worrying about.

  2. If you use Nginx, follow Philip Tellis’s guide to setting up SSL. If you don’t, follow the guide anyway and use the Apache configuration below. Our final configuration differs somewhat from Philip’s recommendation. As an additional step from Philip’s instructions, create a chained CA certificate: "cat sub.class1.server.ca.pem ca.pem > ca.all.pem". You’ll need this file for OCSP stapling.

  3. SSL has its issues. Read up on the SSL BEAST attack, on the theoretical RC4 vulnerability (RC4 is the main way to mitigate the BEAST attack but is itself vulnerable), on OCSP stapling, and on Forward Secrecy (description, implementation and Nginx configuration).

    That last link suggests using "dhparam -rand - 1024" to generate some randomness. If this command doesn’t work for you, try "openssl dhparam -rand - 1024".

  4. Bonus: turn on the SPDY protocol to improve performance for users using SSL. SPDY is supported by Chrome, Firefox (13+), Opera (12+) and Internet Explorer (11+). You will need at minimum OpenSSL 1.0.1, Nginx 1.4 or Apache 2.3 to make all this work. If, like us, you’re using an Ubuntu LTS server that doesn’t have the latest versions, you’ll need to install them from a PPA. We use Chris Lea’s Nginx packages.

Finally, enabling the right cipher suites to get forward secrecy across all modern browsers can be tricky. After much trial and error, we arrived at a very explicit list of cipher suites. Mike Taylor’s list was a great reference. See the configuration below.

Nginx configuration

Assuming you’ve obtained an SSL certificate and installed it as per Philip’s instructions, drop the following configuration into /etc/nginx/conf.d/ssl.conf and disable the SSL configuration in /etc/nginx/sites-available/default. Certificates obtained previously go in the /etc/nginx/ssl folder:

server {
        listen                  443 ssl spdy default_server;
        ssl_certificate         ssl/<your certificate>.pem;
        ssl_certificate_key     ssl/<your certificate>.key; 
        ssl_trusted_certificate ssl/ca.all.pem;

        ssl_session_cache       builtin:1000  shared:SSL:10m;
        ssl_session_timeout     5m;
        ssl_stapling            on;
        ssl_stapling_verify     on;
        ssl_ecdh_curve          secp521r1;

        ssl_protocols           TLSv1 TLSv1.1 TLSv1.2;
        ssl_prefer_server_ciphers       on;

        # The following is all one long line. We use an explicit list of ciphers to enable
        # forward secrecy without exposing ciphers vulnerable to the BEAST attack
        ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-RC4-SHA:ECDHE-RSA-RC4-SHA:ECDH-ECDSA-RC4-SHA:ECDH-RSA-RC4-SHA:ECDHE-RSA-AES256-SHA:RC4-SHA:HIGH:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!CBC:!EDH:!kEDH:!PSK:!SRP:!kECDH;

        # The following is for reference. It needs to be specified again
        # in each virtualhost, in both HTTP and non-HTTP versions.
        add_header Strict-Transport-Security max-age=2592000;
}

SSL is a lower level protocol than HTTP. It encrypts the connection before the HTTP layer has a chance to hear what URL the client is requesting. This means that SSL configuration in a server is independent of virtualhost configuration. Nginx reads its SSL settings from the first server definition it encounters. By placing your configuration in the conf.d folder, which is read before the sites-enabled folder (on Debian-based distributions at least), you are reducing your actual virtualhost configuration to something as simple as this:

server {
        listen 443 ssl spdy;
        server_name hasgeek.com;
        add_header Strict-Transport-Security max-age=2592000;
        root /var/www/hasweb;
        # ...
}

The Strict-Transport-Security header instructs your browser to use HTTPS only for all requests to this domain for the specified period (259,2000 seconds = 30 days). Any HTTP links pointing to your domain will be automatically rewritten to HTTPS by compliant browsers. You will need additional configuration for the first time someone tries accessing over HTTP or using alternative domain names:

server {
        server_name hasgeek.com www.hasgeek.com hasgeek.in www.hasgeek.in;
        add_header Strict-Transport-Security max-age=2592000;
        return 301 https://hasgeek.com$request_uri;
}

server {
        listen 443 ssl spdy;
        server_name www.hasgeek.com hasgeek.in www.hasgeek.in;
        add_header Strict-Transport-Security max-age=2592000;
        return 301 https://hasgeek.com$request_uri;
}      

Apache configuration

We don’t use Apache for any of our primary services, so this configuration is not as thorough as that for Nginx. Assuming a Debian-based distro such as Ubuntu:

  1. Turn on SSL in Apache. Type "sudo a2enmod ssl" (thanks, Kingsly John!)
  2. Drop your certificates in /etc/ssl/private
  3. Add the following directives to /etc/apache2/mods-enabled/ssl.conf:

    # The following is all one long line
    SSLCipherSuite ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-RC4-SHA:ECDHE-RSA-RC4-SHA:ECDH-ECDSA-RC4-SHA:ECDH-RSA-RC4-SHA:ECDHE-RSA-AES256-SHA:RC4-SHA:HIGH:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!CBC:!EDH:!kEDH:!PSK:!SRP:!kECDH;
    
    SSLHonorCipherOrder on
    SSLProtocol all -SSLv2
    
  4. In /etc/apache2/sites-available/default-ssl, turn on named virtual hosting before the VirtualHost block:

    NameVirtualHost *:443
  5. Further down in the same file, point to your certificates:

    SSLCertificateFile /etc/ssl/private/<your certificate>.pem
    SSLCertificateKeyFile /etc/ssl/private/<your certificate>.key
    SSLCACertificateFile /etc/ssl/private/ca.all.crt
    

Test your configuration with sudo apache2ctl configtest, and if all is fine, you are ready to go.

* The archived DocType HTML5 is still on HTTP because it is not hosted on our servers. That site predates HasGeek’s formation and there was no incentive to move it to a new server thus far.

Comments? Discuss this post on HackerStreet.

Update (Nov 2013): Mozilla has posted a comprehensive guide to server-side TLS.