Home :: About Us


Preventing SQL Injection with MySQL and PHP

Most new web developers have heard of SQL injection attacks, but not very many know that it is fairly easy to prevent an attacker from gaining access to your data by filtering out the vulnerabilities using MySQL extensions found in PHP. An SQL injection attack occurs when a hacker or cracker (a malicious hacker) attempts to dump the data in a database table in a database-driven web site. In an unprotected and vulnerable site, this is pretty easy to do.

In order for an SQL injection attack to work, the site must use an unprotected SQL query that utilizes data submitted by a user to lookup something in a database table. The data could be from a search box, a login form or any type of query used to look up data using data input by user. It also means that querystring data used to query a database can create vulnerabilities.

For example:

An very simple unprotected query might look like this:

SELECT * FROM items WHERE itemID = '$itemID'

Normally, you would expect a user to submit a username and password, which would be used to query the database table to see if the username and password exists. But what if someone used the following instead of a password?

‘ OR ‘1′ = ‘1

That would make the query used to look for the password look like this:

SELECT * FROM items WHERE itemID = '' OR  '1' = '1'

This would always return a True response and could literally display the entire table as the result for the query. This is a pretty scary thought if you are trying to keep your data secure. The problem with SQL injection is that a hacker does not have to know anything about your database or table structure.

What if an error or some other issue caused your table structure to be exposed? Hackers are very good at forcing errors to occur that expose information that allows them to penetrate a site deeper. What if the following was entered in the password field?

‘; drop table users;

There is a method for filtering the data that is used on the right side of the WHERE clause to look up a row in a database. The trick is to escape any characters that may be in the user input portion of the query that could lead to a successful attack.

Use the following function to add backslashes to suspect characters and filter any data that is input by a user.

function cleanQuery($string)
{
  if(get_magic_quotes_gpc())  // prevents duplicate backslashes
  {
    $string = stripslashes($string);
  }
  if (phpversion() >= '4.3.0')
  {
    $string = mysql_real_escape_string($string);
  }
  else
  {
    $string = mysql_escape_string($string);
  }
  return $string;
}

// if you are using form data, use the function like this:
if (isset($_POST['itemID'])) $itemID = cleanQuery($_POST['itemID']);

// you can also filter the data as part of your query:
SELECT * FROM items WHERE itemID = '".  cleanQuery($itemID)."' "

The first part looks to see if magic quotes is turned on. if so, it may have already added backslash escapes though a POST or GET method used to pass the data. If backslashes were added, they need to be removed prior to running it through the rest of the function.

The next part checks the PHP version. The built-in function that we want to use is called mysql_real_escape_string. This MySQL function only exists in PHP version 4.3.0 or newer. If you are using an older version of PHP, another MySQL function is used called mysql_escape_string.

mysql_escape_string is not as effective as the newer mysql_real_escape_string. The newer version escapes the string according to the current character set. The character set is ignored by mysql_escape_string, which can leave some vulnerabilities ope for sophisticated hackers. If you find that you are using an older version of PHP and you are trying to protect sensitive data, you really should upgrade to a current version of either PHP 4 or PHP 5.

So what does mysql_real_escape_string do?

This PHP library function prepends backslashes to the following characters: \n, \r, \, \x00, \x1a, ‘ and “. The important part is that the single and double quotes are escaped, because these are the characters most likely to open up vulnerabilities.

For those who do not know what an escape is, it is a character that is pre-pended to another character. When a character is escaped, it is ignored by the database. In other words, it makes that character ineffective in a query. In the case of PHP, an escaped character is treated differently by the PHP parser. The standard escape character used by PHP and MySQL is the backslash.

In the case of the SQL query example used above, after running it through the routine, it now looks like this, which breaks the query :

SELECT * FROM items WHERE itemID = '\' OR \'1\' = \'1'

This method should stop the bulk of the SQL injection attacks, but crackers and hackers are very creative and are always finding new methods to break into systems. There are additional steps that can be taken to filter out certain words, such as drop, grant, union, etc., but using this method will strip these words from searches performed by you users. However, if you want to add another level of security and do not have an issue with certain words being deleted from queries, you can add the following just before if (phpversion() >= ‘4.3.0′).

$badWords = "(delete)|(update)|(union)|(insert)|(drop)|(http)|(--)";
$string = eregi_replace($badWords, "", $string);

This additional step should prevent a malicious attacker from damaging a database if they found a way to slip through. Just remember that is you take this additional step and you have a site where someone might search for a “plumbing union” or a “drop cloth”, those queries would not work as intended.

Another important step that needs to be taken with any database is controlling user privileges. When setting up a MySQL user, you should never assign any more privileges than they actually need to accomplish the tasks that you allow on your site. Privaleges are easily assigned and managed thought phpMyAdmin, which is found in the the control panel (cPanel, Plesk, etc.) for most hosting companies.

Share and Enjoy:
  • Digg
  • del.icio.us
  • StumbleUpon
  • Technorati
  • Furl
  • Reddit

8 Responses to “Preventing SQL Injection with MySQL and PHP”

  1. BestWebHosting Says:

    I suppose PHP 5 should already fixed and prevent SQL injection, am I right ?

  2. TE Says:

    I can’t find a definitive answer on that one. If you have a link to a resource, please post it.

    SQL injection is more of a database issue than a PHP issue. Current versions of MySQL do prevent some types of multiple queries from being executed, which can stop a few types of SQL injection attacks.

    I suspect that PHP 5 does not resolve the issue because SQLite, the new database bundled with PHP 5, is already gaining notoriety as a database that may be particularly vulnerable to injection attacks.

    I’m running a server with PHP 5, but I will still use the cleanQuery function until someone proves to me that I don’t need it.

  3. sundeep Says:

    Thank you very much. The above code has worked for me

  4. srini Says:

    Thanks it worked for me

  5. Kuro Says:

    How about trying $string = addcslashes($string,’;%_:$&?-+=*[]()¡”"´`’); ?

  6. TE Says:

    Hi Kuro

    You can escape any characters that you want, but most of those characters have nothing to do with SQL injection. MySQL recommends using mysql_real_escape_string to protect against SQL injection. You can do anything you want beyond that to protect against cross-site scripting or other vulnerabilities. mysql_real_escape_string just focuses on SQL injection.

  7. vabuk Says:

    Good article

    But you can use strip_tags function of php to remove tag from search terms

    thanks

  8. TE Says:

    I think you may misunderstand the SQL injection issues.

    strip_tags doesn’t do anything to prevent SQL injection. SQL injection requires SQL commands, which strip_tags does not remove. strip_tags is a PHP function that just removes HTML tags.

    In most cases, mysql_real_escape is all that is needed. That is what is recommended by MySQL.

Leave a Reply