If we have internet-facing web servers (and other types of server, for that matter) we care about how vulnerable they are to attack. There are loads of services out there that you can use to probe your public-facing systems, and they'll tell you loads of useful stuff about why they might be vulnerable. But of course they're only useful if you understand what on Earth the probe service is telling you.
We're going to take a canter through the five flaws that are generally considered the most important in the world of internet-facing servers, courtesy of the most recent list from the Open Web Application Security Project, better known as OWASP , explain what each of them actually means, and point at how you can protect yourself.
There are various types of “injection” attack – the one I see most is the SQL injection. These attacks happen when you've been sloppy (or you've failed to realise how defensive you ought to have been) in writing the code that sits behind your website and interprets what's sent to it from forms and the like.
Imagine you run a directory services website; the user enters a surname and your back-end code searched for that name and returned the results using a simple query. Imagine we'd entered the name “Smith”, and it capitalised the string, pulled it into the query and ran it:
SELECT * FROM directory WHERE UPPER(surname) = 'SMITH' ;
All well and good. But what if, instead of “Smith”, we entered the string:
X' ; DELETE FROM users WHERE 1=1; SELECT * FROM users WHERE '' = '; The resulting query would become:
SELECT * FROM directory WHERE UPPER(surname) = 'X' ; DELETE FROM users WHERE 1=1; SELECT * FROM users WHERE '' = '' ; ;
Perfectly valid query to many databases – multiple queries strung together separated by semicolons will be executed in turn. So as long as there's a table called “users”, this will try to delete it. The intruder won't care about what the SELECTs do – just that the query set is valid and doesn't get thrown out by the parser so that the DELETE gets executed.
Injection attacks are easy to mitigate: most Web programming systems have functions that will sanitise input strings (e.g. by converting, a ' into a double '' so it's guaranteed to be treated as a data character instead of being allowed to form part of a command), and if your database allows parameterised queries then use that too. And don't run the database connection under a user ID that has permission to delete stuff it shouldn't. So long as the raw string can't get executed by the database, you're good. (Incidentally, this string conversion is called “escaping” the special characters such as quotation marks. Ask Mr. Google about “escaping SQL strings” and he'll elaborate for you).
Careless session management
If your website has a mechanism for users to log in in order to access some of the content, you'll probably use some kind of “session ID” that gets passed between the browser and the server. When the user logs in the server issues a unique session ID, and the browser passes that in with every subsequent request. Often the ID will be passed in the query itself:
That's fine in principle, but you need to be careful at the server end. You'll usually have a table in your site's back-end database recording current session IDs, and will remove a session when the user hits the “Log out” button. But if they just quit the browser instead of logging out, someone else could fire it up later and land right back in their session if the session is still considered current at the server end.
There's no hard and fast solution (which is why you often see big notices saying “MAKE SURE YOU LOG OUT IF YOU'RE ON A PUBLIC PC” on sites) but you can at the very least have a function that throws away sessions after a few minutes of disuse. This doesn't help if the illicit user gets in quickly, but it's a start.
Cross-site scripting (referred to as “XSS”)
I'm surprised this wasn't number 1 in the OWASP list as it's the one I see most, but at least it's in the top five. The “cross site” bit is all about the attacker being able to inject something into a particular site that causes innocent users unwittingly to access a different site.
Hi, good to see you all
You've probably spotted that this type of attack is similar to the SQL injection we looked at earlier: so to protect yourself you simply need to ensure that you're escaping any user input so that it doesn't just blindly get whacked into the system and treated as valid code.
Unchecked object references
You wouldn't present a web page that includes back-end information in the query, would you? For example if a user logs in and his internal account ID is 1029345:
You do? Hmm, I wouldn't. But if you insist, presumably you do some validation so the user can't just change the account number and see someone else's details:
You'd be surprised that this type of daftness exists, but it does. How to avoid it? Use unique, randomised session IDs, never include internal identifiable Ids (account numbers, seqential identifiers, etc) in browser exchanges like this, and verify access permissions with every single page request.
Misconfiguration of security-related components
This one covers a vast range of possible system issues, and in the OWASP context it's not actually restricted to configuration in its literal sense because the category also includes problems with out-of-date software (which may have security bugs that are fixed in later releases). The three genuinely configuration-related issues I've seen most over the years are:
- Leaving diagnostic messages enabled on the server. For instance in an out-of-the box PHP installation you can generally point the browser at http://www.mysite.com/phpinfo.php – which dishes up all the gory information about your server, OS version, database version, PHP version … everything an intruder needs in order to look up your vulnerabilities via Google.
- Default passwords not being changed. Duh!
- Excessive permissions on back-end systems – usually databases. As with the SQL injection example earlier, the connection from your Web server into the back-end system must have the minimum possible privilege so if someone manages to execute (say) a SQL injection that deletes data it's rejected due to a lack of permissions.