Injection flaws, specifically SQL injection vulnerabilities, can present the greatest business risk in a Web application environment. Tom Olzak explains the nature of injection flaws and SQL injection attacks and then makes recommendations for hardening Web applications.
This article is also available as a TechRepublic download.
In this installment of my series on the revised OWASP Top Ten List of Web application vulnerabilities, I take a look at number two on the list--injection flaws. We'll briefly explore injection flaws in general and then dig into more detail on SQL injection vulnerabilities. Susceptibility to SQL injection attacks is potentially the most dangerous application weakness in this category.
What are injection flaws?
In general, injection flaws allow an attacker to manipulate input to change the behavior of an application. This change in behavior can bypass access controls, allowing the attacker to create, change, delete, or read any data the application can access. According to the OWASP, a worst-case scenario would be the complete compromise of the target application.
Injection flaws are caused by assumptions made by developers that the input strings, when processed by an application, will not contain syntactic content. Such an assumption results in the lack of effective input validation.
There are three primary types of injection attacks:
- System calls
- Shell commands
- SQL injection
The rest of this article covers SQL injection attacks in more detail. See Injection Flaws for a more general discussion of injection vulnerabilities.
SQL injection attacks
In this form of injection vulnerability, user input is not filtered. So an attacker can include a SQL statement or an additional parameter that is then run against a database.
There are four basic types of SQL injection attacks, as described by Stephen Kost in his 2004 paper, An Introduction to SQL Injection Attacks for Oracle Developers.
- SQL manipulation--The attacker modifies SQL statements by using various operations (e.g., UNION). She might also change the syntax of a WHERE clause to retrieve additional information.
- Code injection--In a code injection attack, the attacker inserts one or more new SQL statements into existing SQL code. Environments in which the execution of multiple SQL statements per database request is not allowed are generally not vulnerable to this type of SQL injection.
- Function call injection--Inserting database function calls into a SQL statement constitutes a function call injection attack. The inserted calls might make system calls or manipulate data in database tables.
- Buffer overflows--This type of attack is typically successful against unpatched database servers. It consists of manipulating input so as to cause a system failure or to execute malicious code.
Let's take a look at an example of a SQL manipulation attack against an Oracle database. Figure A shows the original code as it was written by the Web application developer with the user name and password as entered by an authorized user.
|Manipulation Example (Expected Input) (Kost, 2004)|
Figure B shows the same code with a user name and password entered by an attacker. Note that the input text includes an OR operator with a condition (a = a) that will always resolve to TRUE. Therefore, because of operator precedence rules, the WHERE clause resolves to TRUE for every row.
|Manipulation Example (Tainted Input) (Kost, 2004)|
Additional attack types and more detailed code examples are available in the SPI Dynamics paper, SQL Injection by Kevin Spett.
Defending against SQL injection attacks
The primary defense against any type of injection attack is input validation. This includes program input received through all interfaces. Figure C depicts four possible sources of Web application input.
|Web application input|
Input from any one of these sources can change how an application accesses, processes, and displays data. For example, attackers might add, delete, or modify URL parameters in a query string. Hidden form fields can be changed and the form resubmitted. Database information, especially fields written by other applications, might be either purposefully or accidentally tainted. The number and types of vulnerabilities are limited only by a system's unique weaknesses and the creativity of the attacker.
The only effective defense against tainted input is to harden application code. The following are some principles development teams should consider:
- Validate everything. Inspect what you expect and reject anything unexpected.
- Perform all validation on the server. Client-side validation is not really validation. For example, it isn't difficult for an attacker to disable script execution on her workstation to prevent input validation, enter malicious invalid form input, and then submit the form.
- Prevent overly informative user error messages. Attackers often search for code injection vulnerabilities by providing specific types of input and then analyzing the resulting error message.
- Use positive filtering instead of negative filtering. In other words, check for what should be present instead of for what shouldn't. Validating for what shouldn't be in the input leaves too many open holes in the validation process; there are too many variations to check. Possible filtering checks include:
- Is it the right data type (string, integer, etc.)
- Is the parameter required
- Is the character set allowed
- Does the input meet minimum and maximum length constraints
- Is NULL allowed
- If numeric, is the input within range constraints
- Does the input cause data duplication, and if so, is it acceptable
- Does the input meet format requirements (e.g., when compared to a regular expression)
- If selected from a list, does the parameter contain a valid value
- Perform internal code reviews or "buddy checks". This involves having your programmers check each other's work. As we'll see later in this series, there are automated ways to perform this task as well. Also, make sure that quality assurance processes include testing not only valid input but also invalid input.
- Eliminate syntactic input. Ensure that unwanted input to form fields will not be executed. Strip quotes or put backslashes in front of them
- Use "least privilege" to limit the rights of the database user.
- Consider using a default deny expression. Kevin Spett
provides the following example of a regular expression that will return
only letters and numbers:
The final word
Like all vulnerabilities caused by failure to validate input, the business risk associated with injection flaws can be significantly reduced with secure development standards. Ensuring that tainted input cannot be executed is an important first step in protecting your network and your data.