One of the things that has always bothered me about Drupal is the way that it sends it’s logins in clear text. It really bothers me when I’m on vacation, and I’m logging into the site from dirty WiFi hotspots and even dirtier hotel room internet connections. I don’t usually log in as user#1, but there isn’t really a good way to log in as a non-admin account when you need to admin the site! And of course there is the issue of moderators and power-users logging into their accounts from Lord-knows-where, leaving them prone to “Starbucks Sniffing”. So now that vacation time is rolling around I made it a goal of mine to setup secure logins at the site.. How hard could it be, right? Shouldn’t take more than 30 minutes.
The basic steps are pretty easy: Configure your server with an SSL Cert and re-write all the pages that you want encrypted from HTTP to HTTPS. Again, how hard could that be?!
When I first started on this mission, I figured I could save a few dollars and generate my own self-signed SSL Cert. Since I only wanted the cert for enabling encrypted pages, I didnt really care about proving the identity of the site. But as I was testing, I quickly realized that if I used a self-signed SSL Cert some browsers would generate warnings and even pop-up messages about not being able to confirm the identity of the website. Because I didn’t want to scare away any of my visitors I decided I should invest a few bucks into a “real” SSL Cert and purchased one online.
Once you have your SSL cert you have to configure it on your server. If you use cPanel/WHM this isnt too difficult, but you will need to have a dedicated IP for the site/domain. Even though I have a dedicated server with several IP’s, the server was sharing a few sites all on the same IP. Because I’m not really too keen on breaking things I let my hosting company change the IP and configure the new SSL cert for me (Tip: always take the easy way out when possible). If you are on a shared/virtual host the whole shared IP thing may be an issue so you might have to purchase a dedicated IP address for your domain. There also seems to be issues with using “shared” SSL certificates in Drupal so you may want to avoid that and invest in your own cert. Check with your hosting company first to see if they support dedicated IP address and individual certificates before you spend any money.
Once your SSL certificate is setup on your server you should be able to view any page as either HTTP or HTTPS without any errors or warnings (or very few warnings – I’ll get to that below). Assuming you’ve made it this far you can use the Drupal SecurePages module to handle the switching (re-writing) between secure (HTTPS) and non-secure (HTTP) pages. I suppose you could just encrypt all your pages and display them all as HTTPS but that is a bit of overkill and you’ll pay a large performance penalty, especially if you get a lot of pageviews. In my infinite wisdom I decided that only the login page, change password page, new account page and all member info pages needed to be encrypted. Some Drupal experts also think that encrypting all admin pages (ADMIN/*) is also necessary, but I’m just not seeing the need. One warning: be sure that you can access your pages via HTTP and HTTPS before trying to use the SecurePages module! Failure to heed this warning, which is also in big, bold letters on the SecurePages project page WILL result in borking your site.. and we all know that a borked site is no fun, especially on a Tuesday.
Installing SecurePages is easy: just copy it to your sites/all/modules directory and enable it in the modules page – but since there is NO documentation, configuring the module can be tricky, especially if you don’t really understand WTF is going on (like me). The basic settings are to enter your non-secure base URL (http://yourdomain.com) and your secure base URL (httpS://yourdomain.com). You probably will also want to put a checkbox in the “Switch back to http pages when there are no matches” option so that pages that you don’t specify that you want encrypted are automatically switched from HTTPS back to HTTP. Finally, click the “Make secure only the listed pages” radio button, and enter the pages that you want to be encrypted. For me this was “user/*” (without the quotations) which will include the login page, forgot password page and ‘create new account’ page (all start with “user”) as well as all the member’s profile pages. Press SAVE and you’re ready to start testing.
The first thing I noticed while checking that everything was working properly is that once I hit an encrypted HTTPS page, every page I visited after that stayed encrypted – they weren’t switching back to standard HTTP. After a few hours of hair-pulling I found a post at Drupal.org that mentioned leaving an extra blank-line in the “pages” list will result in switching between HTTPS and HTTP not working properly – so be sure you backspace-out any extra/blank lines!
The next problem that I ran into is that none of my encrypted pages were “fully” encrypted. In Firefox this resulted in the security padlock with the line through it and a message that read “parts of the page you are viewing were not encrypted before being transmitted over the internet“, and on Internet Explorer a message would pop up about “not all items on this page are secure” (or something like that) – knowing that the majority of my visitors use Internet Explorer, and knowing that this may scare them away, this was a big problem.
Using the “net” tab in Firebug I was able to quickly (ok, it took me half a day to figure out that I even needed to use Firebug and what to look for) pinpoint the problem on the login pages. It seems that the Kontera scripts that I use are not encrypted. So even though my Drupal data was encrypted, the Kontera portions of the page were not, resulting in the warnings. A few more hours of tinkering with the Kontera module and I was able to exclude Kontera from the login pages – now, when someone accesses the login, password reset or create new account pages, they get the full, “Secured page” padlock – yayyy! (only took me a fucking day).
Next, I was finding the same “parts of the page you are viewing were not encrypted before being transmitted over the internet” messages when viewing or editing member’s profile pages. After more tinkering with Firebug, I found that the avatar images on the pages were failing to load as HTTPS. To get around this all i needed to do was add the avatar image paths to the “pages” list to force them to load as HTTPS. I use the Avatar Selection module so the images come from a few different locations, but adding these entries did the trick:
NOW, when viewing a member’s profile page it was also coming up as fully encrypted, little padlock and all.
But now I ran into another issue. By adding the image locations to the “pages” list, now the avatars were being encrypted, no matter where they were located – for example, in every forum post. This was causing slow page-load times and simply would not do. To overcome this, all I had to do was add the same image locations (above) into the “ignore pages:” list. That would make them display as either HTTPS or HTTP, depending on the parent page. w00t!
Finally, the last little issue was that SecurePages will not encrypt logins via the login or Logintoboggan blocks unless you encrypt every page (which we already decided is a bad thing). So to get around that I created custom “Login” blocks, that direct logins to the /login page which is configured for HTTPS.
So my 30 minute job to enable secure SSL logins ended up taking about 26 hours, but it was fun.. sorta.. Hopefully you can learn from my mistakes and only waste half the time I did. Worst part is, I doubt that most members will even notice or appreciate the lengths I’ve gone to or the hair I’ve pulled out to protect their passwords. But.. I suppose I will sleep better when I’m on vacation.
Closing Thought: Encrypting your login pages is not going to make your site or your member’s accounts hack-proof – but much in the same way that one of those steering-wheel lock-bars on your car wont prevent it from being stolen, it will make it just a bit more difficult, and in this case, 256 bits more.