Understanding the threat landscape is vital to ensuring software is developed and maintained as securely as practically possible. Recent high profile cases of data theft and poorly developed "secure" online services serve to remind us that effective development and testing methodologies must not neglect security.
Security is inevitably compromised for the sake of usability (the best security policy would eschew all public access). However, this is no excuse for poor design and development. This series will highlight the top 10 security vulnerabilities as determined by the Open Web Application Security Project (OWASP).
We kick off this security series with the top security risk according to the OWASP top 10 for 2010 - Injection.
According to OWASP, Injection occurs "when an application sends untrusted data to an interpreter". Typically this takes the form of a user input having unintended consequences. The user input may not obviously be so, such as a web URL link. Nevertheless it can be manipulated by a user for nefarious purposes and is therefor an attack vector.
A typical injection scenario using PHP and SQL
A user is presented with a login screen to access a secure area consisting of a username and password field. The test for authentication in this example is that a record is successfully returned from the database for the username and password submitted. The underlying SQL code will verify the user's credentials as follows:
$sql = "SELECT * FROM user WHERE user_name='" . $_POST['username'] .
"' AND password='" . md5($_POST['password']) . "'";
The expected sql statement above for example user "felix" is:
SELECT * FROM user WHERE user_name='felix'
This will return a record set with 1 result if the username and password are correct, or an empty record set if authentication fails. Consider if a user enters the following into the form user name field:
' OR '1'='1'; --
The sql statement becomes:
SELECT * FROM user WHERE user_name='' OR '1'='1'; -- ' AND password='d41d8cd98f00b204e9800998ecf8427e'
This will return a record set with every user record. Given that authentication is determined in our example by returning a record result, the user will be granted access to the site, and is likely to be granted the privileges of the first user in the record set - typically the administrator!
Preventing injection requires recognising all possible input vectors and sanitising these to ensure only the expected inputs can occur. For the example above this would entail passing all inputs through the mysql_real_escape_string() function. Each application interpreter will have its own methods and recommendations for sanitising inputs to prevent injection attacks (Eg Bash, C, etc) which all developers should be informed of.
For PHP development, a good PHP framework (CodeIgniter, Zend, etc) will provide the required tools to sanitise all SQL input to prevent these attacks via variable binding of inputs and other methods depending on the requirements. Other injection targets such as LDAP may also be supported by your chosen framework.
It is advisable to ensure all input parameters are filtered regardles of their origin to prevent 2nd order injection (where the attack was saved to a database for example and then passed to an interpreter as a trusted input). By treating all parameterised data as untrustworthy (IE not just user inputs) and filtering it, your code will be safe from injection attacks.
In conclusion, whilst relatively simple to prevent, Injection remains the #1 security risk according to OWASP due not only to the ease of exploitation and the potentially severe impact that may result, but more worryingly the prevalence of vulnerable applications. Its prevention requires constant vigilance and oversite of the development process to ensure that all possible opportunities for injection attacks are eliminated.
Next in this series we will look at the #2 risk from OWASP - Cross Site Scripting (XSS)