Home :: About Us :: Guidelines

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 With Your Friends:
  • Digg
  • del.icio.us
  • StumbleUpon
  • Technorati
  • Reddit
  • Facebook
  • LinkedIn
  • Twitter
  • email

19 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.


  9. TW Says:

    TE: I’m not sure I agree with “SQL injection is more of a database issue than a PHP issue.”
    SQL injection is all about lack of/poor validation of user provided data. There is no way an sql database can know that the sql statement it receives is from a good piece of code or from a malicious user. All it can check is syntax. It is entirely up to the code (in this case PHP) to make sure it only passes the SQL statements it wants run to the database.


  10. TE Says:

    Hi TW

    I agree with you, but you have to put my statement into context. The user made a comment about the SQL injection issue being fixed in PHP5. I don’t think that PHP itself can automatically fix the problem. You still have to filter any user input using PHP, but mysql_real_escape_string is a MySQL function executed through PHP. mysql_real_escape_string is a MySQL library function that doesn’t exist unless MySQL is installed.

    That’s why I referred to it as a database issue. The MySQL team provides the recommended solution.


  11. Ryan T. Graff Says:

    Injection is an SQL problem, the closure for commands to a DB should have never been made to be determined by a String which could be mixed with data intended to be entered into a DB. The language is flawed.


  12. Mat Says:

    Thank you,

    This has helped allot. Althou i already used the msql injection to avoid that as i am using latest php 5 version i now got words filtered aswell.

    Cheers!

    Great info and great site.


  13. demon Says:

    Nice info. How do you think about using ctype_alnum() to prevent anything but alphanumeric from being submitted, and ctype_digit() to allow numerical input only?


  14. Doogie Says:

    Hi demon

    They can be useful for validating user input using PHP, but they do not have anything to do with SQL injection.

    There is also ctype_alpha(), which validates a string for alphabetic characters only.

    I think we need to do an article explaining how to use these functions. Thanks for the info. The code monkeys reading this will find it to be useful. :)


  15. Paul Says:

    hey thanks for the great source code, I’ve been developing web for about a 3/2 years now and until recently I never took any heave to the security issue. It’s only recent that I started learning and your article really lightened me up on some parts. Thanks again :)


  16. boaz Says:

    why not use stored procedures in addition to escaping characters? that way your scripts are safe, and you have full control over what the script does.


  17. Doogie Says:

    Hi boaz

    Stored procedures can be a good idea and add another layer of security, but this article only covers SQL injection. Stored procedures work with MySQL 5.0 and newer versions of MySQL, so they are fairly new to MySQL users, but are commonly used with other, older database systems. Quite frankly, I have not seen any MySQL applications using them thus far. I know that some developers think that it adds more complexity to the code, and thus intentionally avoid using them unless it is absolutely required for security.

    I’ve added MySQL Stored Procedures to a series of upcoming security articles. Thanks for the tip. :D


  18. boaz Says:

    Hi Doogie,
    Stored procedures are indeed an advanced feature of database development. I look forward to reading your articles on them. Is there a way I could add myself to an emailing list of yours?

    Thanks! :)


  19. Doogie Says:

    Hi boaz

    We do not use an e-mail list, but we do use Twitter. A tweet goes out to followers with each new article.

Leave a Reply