Download as pdf or txt
Download as pdf or txt
You are on page 1of 3

PHP Programming/SQL Injection Attacks

0.1

1 Use of mysql_real_escape_string()

The Problem

Consider the following SQL query in PHP:


$result=mysql_query('SELECT * FROM users WHERE
username="'.$_GET['username'].'"');
PHP provides you with a function to deal with user input
in MySQL, and that is mysql_real_escape_string(string
unescaped_string[, resource link_identier]). This script
escapes all potentially dangerous characters in the string
provided and returns the escaped string such that it
may be safe to put into a MySQL query. However, if you do not sanitize input prior to passing it to mysql_real_escape_string() function you still
may have SQL injection vectors.
For example;
mysql_real_escape_string would not protect against an
SQL injection vector such as the following:

The query selects all rows from the users table where the
username is equal to the one put in the query string. If
you look carefully, you'll realise that the statement is vulnerable to SQL Injection - quotes in $_GET['username']
are not escaped, and thus will be concatenated as part of
the statement, which can allow malicious behaviour.
Consider what would happen if $_GET['username'] was
the following: " OR 1 OR username = " (a double-quote,
followed by a textual " OR 1 OR username = " followed by
another double-quote). When concatenated into the original expression, you have a query that looks like this: SELECT * FROM users WHERE username = "" OR 1 OR
username = "". The seemingly redundant OR username
= " part added is to ensure that the SQL statement evaluates without error. Otherwise, a hanging double quote
would be left at the end of the statement.

$result = SELECT elds FROM table WHERE id =


".mysql_real_escape_string($_POST['id']);
If $_POST['id'] contained 23 OR 1=1 then the resulting
query would be:
SELECT elds FROM table WHERE id = 23 OR 1=1

This selects all rows from the users table.

which is a valid SQL injection vector.


(The original function, mysql_escape_string, did not take
the current character set in account for escaping the
string, nor accepted the connection argument. It is deprecated since PHP 4.3.0.)

0.2

The Solution

For example, consider one of the examples above:


$result=mysql_query('SELECT * FROM users WHERE
username="'.$_GET['username'].'"');

Never trust user provided data, process this data only after validation; as a rule, this is done by pattern matching.
In the example below, the username is restricted to alphanumerical chars plus underscore and to a length between eight and 20 chars - modify as needed.

This could be escaped as follows:


$result=mysql_query('SELECT
*
FROM
users
WHERE
username="'.mysql_real_escape_string($_GET['username']).'"');

if (preg_match("/^\w{8,20}$/", $_GET['username'],
$matches)) $result = mysql_query(SELECT * FROM
users WHERE username=$matches[0]"); else // we
don't bother querying the database echo username not
accepted";

This way, if the user tried to inject another statement such


as a DELETE, it would harmlessly be interpreted as part
of the WHERE clause parameter as expected:

SELECT * FROM `users` WHERE username =


For increased security, you might want to abort the '\';DELETE FROM `forum` WHERE title != \''
The backslashes added by mysql_real_escape_string
scripts execution replacing echo by exit() or die().
This issue still applies when using checkboxes, radio make MySQL interpret them as actual single quote charbuttons, select lists, etc. Any browser request(even acters rather than as part of the SQL statement.
POST) can be replicated through telnet, duplicate sites, Note that MySQL does not allow stacking of queries so
javascript, or code (even PHP), so always be cautious of the ;DELETE FROM table attack would not work anyway
any restrictions set on client-side code.
1

4 FOR MORE INFORMATION

Use Parameterized Statements

The PEARs DB package provides a prepare/execute


mechanism to do parameterized statements.
require_once(DB.php); $db = &DB::connect("mysql:
//user:pass@host/database1");
$p
=
$db>prepare(SELECT * FROM users WHERE username
= ?"); $db->execute( $p, array($_GET['username']) );
The query() method, also do the same as prepare/execute,
$db->query( SELECT * FROM users WHERE username = ?", array($_GET['username']) );
The
prepare/execute
will
automatically
call
mysql_real_escape_string() as discussed in the above
section.
In PHP version 5 and MySQL version 4.1 and above, it is
also possible to use prepared statements through mysqli
extension[1] . Example[2] :
$db = new mysqli(localhost, user, pass,
database); $stmt = $db -> prepare(SELECT
priv FROM testUsers WHERE username=? AND
password=?"); $stmt -> bind_param(ss, $user, $pass);
$stmt -> execute();
Similarly, you could use the built-in PDO Class in PHP5.

References

[1] Ocial documentation for Mysqli extension, php.net.


[2] Prepared Statements in PHP and MySQLi, Matt Bango.

For More Information


PHP Manual: SQL Injection
UC Santa Cruz: SQL Injection Attacks
How to prevent SQL Injection Attacks
PHP/MySQL Injection Video
Preventing SQL Injection in PHP MySQL Insert
and Update Queries
Preventing SQL Injection in PHP MySQL Select
Queries

Text and image sources, contributors, and licenses

5.1

Text

PHP Programming/SQL Injection Attacks Source: http://en.wikibooks.org/wiki/PHP%20Programming/SQL%20Injection%


20Attacks?oldid=2756940 Contributors: Spoom, Mybot99999, Redlentil, Arthaey, Marek, Monkeymatt, Austinb, Derbeth, Trince,
Ans, Jguk, AdRiley, Dandaman32, Rdivilbiss, Mikes bot account, QuiteUnusual, Adrignola, Philoertel, JenVan, Sonia, Sae1962 and
Anonymous: 49

5.2

Images

File:Navigation_Left_Arrow.svg Source: http://upload.wikimedia.org/wikibooks/en/d/df/Navigation_Left_Arrow.svg License: Cc-bysa-3.0 Contributors:


self-made
Original artist:
Arun Reginald
File:Navigation_Right_Arrow.svg Source: http://upload.wikimedia.org/wikibooks/en/e/ea/Navigation_Right_Arrow.svg License: Ccby-sa-3.0 Contributors:
self-made
Original artist:
Arun Reginald

5.3

Content license

Creative Commons Attribution-Share Alike 3.0

You might also like