Main image of article A Brute Force Defense Against Injection Attacks

Injection attacks are a common security problem for Web developers. The interpreted nature of most development languages makes them especially vulnerable to these attacks. This article explains what an injection attack is and provides some simple steps that you can take to defend your site against them.

Injection ShieldWhat is an Injection Attack?

An injection attack takes place when a malevolent programmer puts code in the query string or other parts of the HTTP request. The interpreter executes the malicious code, usually opening the browser and/or server up to more exploits.

Popular open-source components and CMS tools are especially vulnerable because potential attackers can examine the code for weaknesses, then automate attack attempts against them. When a website is compromised, the site can become a danger to any visitor who happens upon it.

When someone gets code to execute on your server that you don't intend, your sever could expose confidential data, your content could be deleted or altered, and access by you or your legitimate users could be limited or denied. An attacker could also compromise your site so that it infects your visitors' computers with malware using known browser vulnerabilities.

The Best Defense

The best defense against injection attacks is to develop secure habits and adopt policies and procedures that minimize vulnerabilities. Staying aware of the types of attacks you're vulnerable to because of your programming languages, operating systems and database management systems is critical.

For example, data-driven websites and applications are especially vulnerable to SQL injection attacks. To defend against these, you should never put unfiltered data from the HTTP query string directly into a database query. Instead, parameterize the input when you need to use it raw from the HTTP query string.

Here's a classic example of SQL Injection into a PHP program, and a common defense against it.

// THIS CODE IS VULNERABLE TO SQL INJECTION
$name = $_GET['username'];
$password = $_GET['password'];
$sql = "SELECT * FROM password WHERE name = '$name' AND password='$password'";
$result = mysql_query($sql);

If an attacker were to to enter the following into the form:

' OR 1=1 --

The code would look like this when $password was substituted:

$sql = "SELECT * FROM password WHERE name = '$name' AND password='' OR 1==1 --'";

As you can see, this would always evaluate to true.

However, if the following equivalent code (which uses PDO) were used in its place, the attack attempt would fail:

$name = $_GET['name'];
$password = $_GET['password']
$sql = "SELECT * FROM table WHERE name = ? AND password = ?";
$q = $conn->prepare($sql);
$q->execute(array($name,$password));

At the end of this article, I've included a list of websites that have excellent advice about how to develop secure coding habits.

Vulnerability in Others' Code

Today, most websites and applications aren't built from scratch. Web apps and data-driven sites are created using a wide range of open-source components, libraries, frameworks and code snippets, along with the developer's original code. It's extremely uncommon for a developer to code an entire application from scratch.

The more popular an open-source component, library or framework becomes, the more likely it is to attract the attention of malevolent programmers who'll examine it for exploitable flaws.

Several years ago, I decided to create a simple "brute force" defense against injection attacks in PHP after a site I maintained was compromised. I had decided to use a popular CMS platform and found the "perfect" plugin — which had an exploitable security flaw. I realized that if I were to continue to use other people's code, I needed a fast, reliable way to ensure better security.

This simple brute force approach sanitizes the superglobals that PHP uses to process input from the query string. I simply needed to put this injection shield at the top of each entry point (for example at the top of index.php) and all user input was sanitized.

<?
include_once('InjectionShield.php');
?>

Introducing the OWASP Reform Library

The injection shield uses the OWASP Reform Library to sanitize the input. OWASP is the Open Web Application Security Project, a worldwide not-for-profit organization focused on improving the security of software. One of its libraries, the Reform Library, created by Michael Eddington, is the cornerstone of the Injection Shield. The library will encode any character that doesn't fall into a normal alphabet of characters. In addition, it encodes all Unicode characters.

<?php
include('Reform.php');
$reform = new Reform;
php>
<body>
Hello, your name is <?php echo $reform->HtmlEncode(
"<script>alert('meow')</script>"); ?>.
</body>

Is output to ...

<body>
Hello, your name is
<script>alert('meow')&#60/script>.
</body>

The following code snippet is the basis of the Injection Shield.

$reform = new Reform;
foreach(array_keys($_GET) as $k)
{
$_GET[$k] = $reform->HtmlEncode($_GET[$k]);
}

The HTMLEncode method is more extensive than the htmlentities function that's included with PHP, though that may work as well. A copy of the PHP Reform library is included with the downloadable source code at the end of this article. For the latest version of the full library, visit the OWASP Encoding Project.

A Problem With Brute Force

The following url contains both valid information and an attempt at a file inclusion attack:

http://example.com/InjectionShield/example.php?email=dude@example.com&password=A1!B2@b3.b4&file=ftp://example.com/evil/my_evil_file.php

Then example.php looks something like this:

<?
error_log("Before Injection Shield:".var_export($_REQUEST,true));
include_once('InjectionShield.php');
error_log("After Injection Shield:".var_export($_REQUEST,true));
?>

An examination of the error log in a code editing program — not a Web browser — reveals what you see below. (The reason you don't want to use a browser is that it will translate those HTML Entities into viewable characters.)

no_exceptions

Notice that both the email and the password were sanitized along with the attempted exploit. It's unlikely that subsequent processes will be able to use the sanitized email address, and the password may not match the original.

A Solution

Since my purpose was to sanitize input before passing it to others' code, I decided to encapsulate the functionality in an "Injection Shield" class so I could not sanitize input that I would handle myself. By default, everything is sanitized. However, the constructor accepts an array of exceptions that aren't sanitized, so I can validate them myself without altering their integrity. I also designed it so I could pick and choose which input streams were to be sanitized.

<?
include_once('InjectionShield.class.php');
$exceptions = array('email','password');
$shield = new InjectionShield($exceptions);

// If you are expecting an email address, you might not want it sanitized, so validate it explicitly
if ($_REQUEST['email']) // This could be repeated for $_GET and $_POST
{
$_REQUEST['email'] = filter_var($_REQUEST['email'], FILTER_VALIDATE_EMAIL);
}
// Always hash a password - right?
if ($_REQUEST['password']) // or $_GET OR $_POST ...
{
$salt = 'some salt value';
$_REQUEST['password'] = hash('whirlpool',$_REQUEST['password'].$salt);
}

?>

Here's is the output that results from the code above:

with_exceptions

Notice that the code I intend to use in my program is in the validated format that I need, but the unexpected input file has been sanitized.

The Injection Shield class also recursively sanitizes arrays within the query strings and allows you to sanitize any array, not just the PHP superglobals.

Obviously, this brute force approach doesn't elegantly detect sophisticated intrusion attempts, and if you don't handle exceptions well, your code will either be vulnerable or won't work properly. However, it does make the code "Secure by Default." I've found this technique to be useful while pursuing more elegant special cases.

Resources

Download Source Code and Example Usage for the PHP InjectionShield.

The following sites contain simple examples of injection attacks:

I've found the following articles to be extremely helpful to understanding injection attacks:

While it's vital to stay aware of "everything," generally speaking, I've found the OWASP site to be the single best resource for helping me stay aware of ongoing threats to my Web applications.

Image: OpenClipArt.org