Lesson Learnt: Secure Your Website
Posted on Feb 16, 2011 in Programming
An interesting thing happened to me recently: A small security hole in my website was exploited. It was hardly a big deal, but someone managed to submit content to some of my project documentation pages and fill them with generic ads and spam. I've since plugged the hole, but it's a bit of a reminder that I have to be very careful about keeping my site secure and safe from brute-force attacks.
Since I find this kind of stuff rather interesting, let's have a look at what happened, how it happened, how it could have been much worse, and how to prevent these kind of things in the first place.
A Rubbish Discovery
I was scanning some of my own documentation yesterday when I found some rubbish titles in the list of pages. It had only affected two (reasonably short) pages of the documentation, but it still drove a spike of paranoia through my mind. Is there a massive security hole in my website, or even worse, the framework itself?
After a short amount of investigation, I discovered that only one data type was affected - unfortunately it was the documentation pages, which had the most content in it (excluding the blog). A short time later, my backups were restored and the hole was plugged in the code.
What caused the security hole? A commented out line of code in the security settings, which should have been excluding access of the edit page to admin users (i.e. me). Why was it commented out? Who knows, perhaps I was debugging something. The important thing I got out of this is that I'll never make the mistake of forgetting about security again!
Analysis of the Attack
I got rather lucky. The attacker was using some sort of brute-force method of sending content to (I assume) randomly generated URLs in a website. The tool happened to correctly guess two of the URLs as well as the correct postback variable names to pass validation. To get past, not only did the hacker need to guess two postback variable names, but they also had to guess the action name, as well as the parameter value - which is a database id field which is not exposed to public users.
The fact that they managed to get that far is impressive, at least in my eyes. I'm sure most people have seen examples of abandoned websites which simply fill with spam as the automated tools trawl through, creating forum profiles, posting posts full of spam links. This is more predominant on well-known application frameworks such as phpBB and other common forum platforms. Fortunately as my site is custom-made, it is more difficult to guess the correct values. But guess they did, and they hit the mark twice. It did take them 7000 tries, though.
It Could be Much Worse
Let's look at how it could have been worse. If I wrote my documentation to accept pure HTML as input (I would be the only one using it, after all), a spammer could have injected whatever the hell they wanted into my site! This could include malicious javascript, flash content, advertisements, or worse. I happen to be a pretty big user of BBCode, so fortunately the attacker was only able to insert links.
Additionally, I could have lost many more than two pages - all of my Phoenix documentation could have been overwritten. I have the content elsewhere, but not in the same format as the site - it would have taken a reasonable amount of time to get the documentation back up and running. Another lesson: backup your website database often!
Also, imagine if the security hole wasn't only isolated to the one page. All of my content could have been wiped clean! It's rather sobering to think that there's a possibility that someone can do that quite easily.
Prevention
It's not too difficult to prevent this from happening to your own site, but you need to be concerned about security in the first place. Fortunately, I designed Phoenix MVC with security as one of the goals. Here's how Phoenix helps with security.
Authentication
The most obvious security mechanism in Phoenix, authentication is what is used to "log in" to websites. On this site, I use a hybrid authentication of OpenID and regular account creation (I haven't actually written the code to create new accounts yet, which is probably why I haven't had any spam users created yet). Authentication allows you to only let certain, authenticated users to log in and post content.
Authorisation
Authorisation is the next logical layer on top of authentication. It allows some users to have more access than others. It's very easy to restrict certain actions to logged-in users, or users with certain privileges. Phoenix provides several different ways to implement authorisation, as well as the ability to create your own methods if desired.
Parameterised Queries
Parameterised queries are how you stop SQL injection attacks from happening on your site. Phoenix parameterises all SQL queries it creates with the Model and Query classes. It encourages the use of parameters in the database class, as well. SQL injection is a great way for attackers to work-around your authentication system - Phoenix's authentication system uses the Model class, and all queries are parameterised to eliminate the possibility of SQL injection.
Results
Three things that I have taken out of this:
- Don't leave security holes in your website, no matter how obscure
- Back up your website (data and files) regularly
- Use proper security on your website and/or framework
Next week I'll post something a bit less boring, I promise!
