Protecting Your Site Part 2: Preparing SQL Statements

Page 1 - Validating User Input

Skip to navigation

Padlock for Security
Feb
27

It's been almost three years since my last article on web security and now it's time to revisit it with more ways to secure your site, and what to look out for. The assumption for this guide is that you are using PHP and MySQL although many of the tips mentioned here will also be applicable to other languages and DBMS's.

It's not a case of not being able to trust your user, but rather a case of not being able to trust people that enjoy finding exploits in peoples sites. Whether yours has been targeted in the past or not you're bound to want to secure your site in case of any possible attacks in the future. The first two attacks we want to guard against are Cross-Site Scripting (XSS) attacks and SQL injection. We've looked at both of these before, but there are a few pointers that will help to increase your security even further.

Last time we looked at XSS we dealt with encoding issues - but that is not always enough. Let us consider a number of examples that may affect your site such as a real world example using eBay Communities. I know someone who runs an eBay community for Star Wars fans and they were recently attacked by someone starting off a new discussion which only contained an opening HTML comment so that when this appeared in the discussion page it had commented out everything on the page after it - this is probably one of the more severe examples you may face of input not being cleansed and it isn't actually an XSS attack - but it is possible to cause the same level of disruption with one such as if some JavaScript was injected into the page that caused session details to be sent to another user. Nowadays the term XSS is also used in reference to a whole myriad of attacks are can quite often be closely linked with SQL injection attacks.

If content that a user can enter or a URL parameter should be a integer then you should ensure it's an integer using the intval() function in PHP for example. If it's a string then you've got a little more work to do abut it should still be easy enough to implement a solution. To avoid "HTML injection" you should strip out any HTML from the string - if you need to allow users to specify formatting then you should use something like BBCode. what could also be a problem is that strip_tags does not take into account any encoding in the string such as UTF-8 or URL encoding but what if the user encodes what is already encoded? Then the solution is to keep decoding until the string doesn't change from decoding. Once you have got this final version you can strip the tags from it and the string should then be safe. One way of doing it is as follows:

$my_input = strip_tags(utf8_decode($_POST['my_input']));
while ($my_input != strip_tags(utf8_decode($my_input))) {
  $my_input = strip_tags(utf8_decode($my_input));
}

It's still not fool proof and it could be tidied up somewhat and made more efficient, but it goes a long way towards validating generic text fields if you do this before displaying it back on the page or saving to the database. This should also extend to other fields such as ones designed to take dates - they should only allow numbers, hyphens, slashes, dots, whitespace and colons - accepting anything else could be potentially risky. 

I took a similar strategy with the search on this site - when the user searches for something it is put back into the search box, is displayed in a paragraph and is used in an SQL statement. I knew it was already reasonably safe against SQL injection due to the way I'd structured the queries - it was still vulnerable to them, but I knew it'd take a bit of digging to find a way of attacking it. The main concern here was from the search box and the search results - it was annoying seeing people able to deface this site - obviously it would only happen to them, but if they posted a link to the site with the XSS attack in the URI then they'd see it too which is something I didn't want! To remedy this issue I took a similar approach to the code I posted above, and so far so good - no more successful attempts!

Before you comment on my incorrect usage of the term XSS, I know, but it seems to be getting commonly misused nowadays to describe this behaviour so I thought I may as well join in. Anyway, let's move on to the more important SQL injection attacks.