Create an account

Very important

  • To access the important data of the forums, you must be active in each forum and especially in the leaks and database leaks section, send data and after sending the data and activity, data and important content will be opened and visible for you.
  • You will only see chat messages from people who are at or below your level.
  • More than 500,000 database leaks and millions of account leaks are waiting for you, so access and view with more activity.
  • Many important data are inactive and inaccessible for you, so open them with activity. (This will be done automatically)


Thread Rating:
  • 838 Vote(s) - 3.53 Average
  • 1
  • 2
  • 3
  • 4
  • 5
How can I prevent SQL injection in PHP?

#11
> **Security Warning**: This answer is not in line with security best practices. [Escaping is inadequate to prevent SQL injection](

[To see links please register here]

), use *prepared statements* instead. Use the strategy outlined below at your own risk. (Also, `mysql_real_escape_string()` was removed in PHP 7.)

> **Deprecated Warning**: The mysql extension is deprecated at this time. we recommend using the *PDO extension*

I use three different ways to prevent my web application from being vulnerable to SQL injection.

1. Use of `mysql_real_escape_string()`, which is a pre-defined function in [PHP][1], and this code add backslashes to the following characters: `\x00`, `\n`, `\r`, `\`, `'`, `"` and `\x1a`. Pass the input values as parameters to minimize the chance of SQL injection.
2. The most advanced way is to use PDOs.

I hope this will help you.

Consider the following query:

`$iId = mysql_real_escape_string("1 OR 1=1");
$sSql = "SELECT * FROM table WHERE id = $iId";`

mysql_real_escape_string() will not protect here. If you use single quotes (' ') around your variables inside your query is what protects you against this. Here is an solution below for this:

`$iId = (int) mysql_real_escape_string("1 OR 1=1");
$sSql = "SELECT * FROM table WHERE id = $iId";`

This [question][2] has some good answers about this.

I suggest, using PDO is the best option.

**Edit:**

`mysql_real_escape_string()` is deprecated as of PHP 5.5.0. Use either mysqli or PDO.

An alternative to mysql_real_escape_string() is

string mysqli_real_escape_string ( mysqli $link , string $escapestr )
**Example:**

$iId = $mysqli->real_escape_string("1 OR 1=1");
$mysqli->query("SELECT * FROM table WHERE id = $iId");


[1]:

[To see links please register here]

[2]:

[To see links please register here]

Reply

#12
>**Deprecated Warning:**
This answer's sample code (like the question's sample code) uses PHP's `MySQL` extension, which was deprecated in PHP 5.5.0 and removed entirely in PHP 7.0.0.

> **Security Warning**: This answer is not in line with security best practices. [Escaping is inadequate to prevent SQL injection](

[To see links please register here]

), use *prepared statements* instead. Use the strategy outlined below at your own risk. (Also, `mysql_real_escape_string()` was removed in PHP 7.)


Using [PDO][1] and [MYSQLi][2] is a good practice to prevent SQL injections, but if you really want to work with MySQL functions and queries, it would be better to use

[mysql_real_escape_string][3]

$unsafe_variable = mysql_real_escape_string($_POST['user_input']);

There are more abilities to prevent this: like identify - if the input is a string, number, char or array, there are so many inbuilt functions to detect this. Also, it would be better to use these functions to check input data.

[is_string][4]

$unsafe_variable = (is_string($_POST['user_input']) ? $_POST['user_input'] : '');
[is_numeric][5]

$unsafe_variable = (is_numeric($_POST['user_input']) ? $_POST['user_input'] : '');

And it is so much better to use those functions to check input data with `mysql_real_escape_string`.

[1]:

[To see links please register here]

[2]:

[To see links please register here]

[3]:

[To see links please register here]

[4]:

[To see links please register here]

[5]:

[To see links please register here]

Reply

#13
>**Deprecated Warning:**
This answer's sample code (like the question's sample code) uses PHP's `MySQL` extension, which was deprecated in PHP 5.5.0 and removed entirely in PHP 7.0.0.

> **Security Warning**: This answer is not in line with security best practices. [Escaping is inadequate to prevent SQL injection](

[To see links please register here]

), use *prepared statements* instead. Use the strategy outlined below at your own risk. (Also, `mysql_real_escape_string()` was removed in PHP 7.)

> **IMPORTANT**
>
> The best way to prevent SQL Injection is to use **Prepared Statements** *instead of escaping*, as [the accepted answer](

[To see links please register here]

) demonstrates.
>
> There are libraries such as [Aura.Sql](

[To see links please register here]

) and [EasyDB](

[To see links please register here]

) that allow developers to use prepared statements easier. To learn more about why prepared statements are better at [stopping SQL injection](

[To see links please register here]

), refer to [this `mysql_real_escape_string()` bypass](

[To see links please register here]

) and [recently fixed Unicode SQL Injection vulnerabilities in WordPress](

[To see links please register here]

).

Injection prevention - [mysql_real_escape_string()][1]

PHP has a specially-made function to prevent these attacks. All you need to do is use the mouthful of a function, `mysql_real_escape_string`.

`mysql_real_escape_string` takes a string that is going to be used in a MySQL query and return the same string with all SQL injection attempts safely escaped. Basically, it will replace those troublesome quotes(') a user might enter with a MySQL-safe substitute, an escaped quote \'.

**NOTE:** you must be connected to the database to use this function!

// Connect to MySQL

$name_bad = "' OR 1'";

$name_bad = mysql_real_escape_string($name_bad);

$query_bad = "SELECT * FROM customers WHERE username = '$name_bad'";
echo "Escaped Bad Injection: <br />" . $query_bad . "<br />";


$name_evil = "'; DELETE FROM customers WHERE 1 or username = '";

$name_evil = mysql_real_escape_string($name_evil);

$query_evil = "SELECT * FROM customers WHERE username = '$name_evil'";
echo "Escaped Evil Injection: <br />" . $query_evil;

You can find more details in *[MySQL - SQL Injection Prevention][2]*.

[1]:

[To see links please register here]

[2]:

[To see links please register here]

Reply

#14
I'd recommend using [PDO][1] (PHP Data Objects) to run parameterized SQL queries.

Not only does this protect against SQL injection, but it also speeds up queries.

And by using PDO rather than `mysql_`, `mysqli_`, and `pgsql_` functions, you make your application a little more abstracted from the database, in the rare occurrence that you have to switch database providers.

[1]:

[To see links please register here]

Reply

#15
Regarding many useful answers, I hope to add some value to this thread.

SQL injection is an attack that can be done through user inputs (inputs that filled by a user and then used inside queries). The SQL injection patterns are correct query syntax while we can call it: bad queries for bad reasons, and we assume that there might be a bad person that try to get secret information (bypassing access control) that affect the three principles of security (confidentiality, integrity, and availability).

Now, our point is to prevent security threats such as SQL injection attacks, the question asking (how to prevent an SQL injection attack using PHP), be more realistic, data filtering or clearing input data is the case when using user-input data inside such query, using PHP or any other programming language is not the case, or as recommended by more people to use modern technology such as prepared statement or any other tools that currently supporting SQL injection prevention, consider that these tools not available anymore? How do you secure your application?

My approach against SQL injection is: clearing user-input data before sending it to the database (before using it inside any query).

**Data filtering for (converting unsafe data to safe data)**

Consider that [PDO][1] and [MySQLi][2] are not available. How can you secure your application? Do you force me to use them? What about other languages other than PHP? I prefer to provide general ideas as it can be used for wider border, not just for a specific language.

1. SQL user (limiting user privilege): most common SQL operations are (SELECT, UPDATE, INSERT), then, why give the UPDATE privilege to a user that does not require it? For example, **login, and search pages** are only using SELECT, then, why use DB users in these pages with high privileges?

**RULE: do not create one database user for all privileges. For all SQL operations, you can create your scheme like (deluser, selectuser, updateuser) as usernames for easy usage.**

See [principle of least privilege][3].

2. Data filtering: before building any query user input, it should be validated and filtered. For programmers, it's important to define some properties for each user-input variables:
**data type, data pattern, and data length**. A field that is a number between (x and y) must be exactly validated using the exact rule, and for a field that is a string (text): pattern is the case, for example, a username must contain only some characters, let’s say [a-zA-Z0-9_-.]. The length varies between (x and n) where x and n (integers, x <=n).
**Rule: creating exact filters and validation rules are best practices for me.**

3. Use other tools: Here, I will also agree with you that a prepared statement (parametrized query) and stored procedures. The disadvantages here is these ways require advanced skills which do not exist for most users. The basic idea here is to distinguish between the SQL query and the data that is used inside. Both approaches can be used even with unsafe data, because the user-input data here does not add anything to the original query, such as (any or x=x).

For more information, please read [OWASP SQL Injection Prevention Cheat Sheet][4].

Now, if you are an advanced user, start using this defense as you like, but, for beginners, if they can't quickly implement a stored procedure and prepared the statement, it's better to filter input data as much they can.

Finally, let's consider that a user sends this text below instead of entering his/her username:

[1] UNION SELECT IF(SUBSTRING(Password,1,1)='2',BENCHMARK(100000,SHA1(1)),0) User,Password FROM mysql.user WHERE User = 'root'

This input can be checked early without any prepared statement and stored procedures, but to be on the safe side, using them starts after user-data filtering and validation.

The last point is detecting unexpected behavior which requires more effort and complexity; it's not recommended for normal web applications.

Unexpected behavior in the above user input is SELECT, UNION, IF, SUBSTRING, BENCHMARK, SHA, and root. Once these words detected, you can avoid the input.

##UPDATE 1:

A user commented that this post is useless, OK! Here is what [OWASP.ORG provided][5]:

> Primary defenses: <br/>
> <br/>
> Option #1: Use of Prepared Statements (Parameterized Queries) <br/>
> Option #2: Use of Stored Procedures <br/>
> Option #3: Escaping all User Supplied Input <br/>
> <br/>
> Additional defenses: <br/>
> <br/>
> Also Enforce: Least Privilege <br/>
> Also Perform: White List Input Validation <br/>

As you may know, claiming an article should be supported by a valid argument, at least by one reference! Otherwise, it's considered as an attack and a bad claim!

##Update 2:

From the PHP manual, [PHP: Prepared Statements - Manual][6]:

> Escaping and SQL injection <br/>
>
> Bound variables will be escaped automatically by the server. The
> server inserts their escaped values at the appropriate places into the
> statement template before execution. A hint must be provided to the
> server for the type of bound variable, to create an appropriate
> conversion. See the mysqli_stmt_bind_param() function for more
> information. <br/>
>
> The automatic escaping of values within the server is sometimes
> considered a security feature to prevent SQL injection. The same
> degree of security can be achieved with non-prepared statements if
> input values are escaped correctly. <br/>

##Update 3:

I created test cases for knowing how PDO and MySQLi send the query to the MySQL server when using a prepared statement:

**PDO:**

$user = "''1''"; // Malicious keyword
$sql = 'SELECT * FROM awa_user WHERE userame =:username';
$sth = $dbh->prepare($sql, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
$sth->execute(array(':username' => $user));

**Query Log:**

> 189 Query SELECT * FROM awa_user WHERE userame ='\'\'1\'\''
> 189 Quit

**MySQLi:**

$stmt = $mysqli->prepare("SELECT * FROM awa_user WHERE username =?")) {
$stmt->bind_param("s", $user);
$user = "''1''";
$stmt->execute();

**Query Log:**

> 188 Prepare SELECT * FROM awa_user WHERE username =?
> 188 Execute SELECT * FROM awa_user WHERE username ='\'\'1\'\''
> 188 Quit

###It's clear that a prepared statement is also escaping the data, nothing else.

As also mentioned in the above statement,

> The automatic escaping of values within the server is sometimes considered a security feature to prevent SQL injection. The same degree of security can be achieved with non-prepared statements, if input values are escaped correctly

Therefore, this proves that data validation such as `intval()` is a good idea for integer values before sending any query. In addition, preventing malicious user data before sending the query is **a correct and valid approach**.

Please see this question for more detail: *https://stackoverflow.com/questions/18026088/pdo-sends-raw-query-to-mysql-while-mysqli-sends-prepared-query-both-produce-the*

References:

1. [SQL Injection Cheat Sheet][7]
2. [SQL Injection][8]
3. [Information security][9]
4. [Security Principles][10]
5. [Data validation][11]

[1]:

[To see links please register here]

[2]:

[To see links please register here]

[3]:

[To see links please register here]

[4]:

[To see links please register here]

[5]:

[To see links please register here]

[6]:

[To see links please register here]

[7]:

[To see links please register here]

[8]:

[To see links please register here]

[9]:

[To see links please register here]

[10]:

[To see links please register here]

[11]:

[To see links please register here]






Reply

#16
**Warning: the approach described in this answer only applies to very specific scenarios and isn't secure since SQL injection attacks do not only rely on being able to inject `X=Y`.**

If the attackers are trying to hack into the form via PHP's `$_GET` variable or with the URL's query string, you would be able to catch them if they're not secure.

RewriteCond %{QUERY_STRING} ([0-9]+)=([0-9]+)
RewriteRule ^(.*) ^/track.php

Because `1=1`, `2=2`, `1=2`, `2=1`, `1+1=2`, etc... are the common questions to an SQL database of an attacker. Maybe also it's used by many hacking applications.

But you must be careful, that you must not rewrite a safe query from your site. The code above is giving you a tip, to rewrite or redirect *(it depends on you)* that hacking-specific dynamic query string into a page that will store the attacker's [IP address][1], or EVEN THEIR COOKIES, history, browser, or any other sensitive information, so you can deal with them later by banning their account or contacting authorities.

[1]:

[To see links please register here]

Reply

#17
Every answer here covers only part of the problem.
In fact, there are **four** different query parts which we can add to SQL dynamically: -

- a string
- a number
- an identifier
- a syntax keyword

And prepared statements cover only two of them.

But sometimes we have to make our query even more dynamic, adding operators or identifiers as well.
So, we will need different protection techniques.

In general, such a protection approach is based on *whitelisting*.

In this case, every dynamic parameter should be hardcoded in your script and chosen from that set.
For example, to do dynamic ordering:

$orders = array("name", "price", "qty"); // Field names
$key = array_search($_GET['sort'], $orders)); // if we have such a name
$orderby = $orders[$key]; // If not, first one will be set automatically.
$query = "SELECT * FROM `table` ORDER BY $orderby"; // Value is safe

To ease the process I wrote a [whitelist helper function](

[To see links please register here]

) that does all the job in one line:

$orderby = white_list($_GET['orderby'], "name", ["name","price","qty"], "Invalid field name");
$query = "SELECT * FROM `table` ORDER BY `$orderby`"; // sound and safe

There is another way to secure identifiers - escaping but I rather stick to whitelisting as a more robust and explicit approach. Yet as long as you have an identifier quoted, you can escape the quote character to make it safe. For example, by default for mysql you have to [double the quote character to escape it](

[To see links please register here]

). For other other DBMS escaping rules would be different.

Still, there is an issue with SQL syntax keywords (such as `AND`, `DESC` and such), but white-listing seems the only approach in this case.

So, a general recommendation may be phrased as

> - Any variable that represents an SQL data literal, (or, to put it simply - an SQL string, or a number) must be added through a prepared statement. No Exceptions.
> - Any other query part, such as an SQL keyword, a table or a field name, or an operator - must be filtered through a white list.

### Update

Although there is a general agreement on the best practices regarding SQL injection protection, there are **still many bad practices as well.** And some of them too deeply rooted in the minds of PHP users. For instance, on this very page there are (although invisible to most visitors) **more than 80 deleted answers** - all removed by the community due to bad quality or promoting bad and outdated practices. Worse yet, some of the bad answers aren't deleted, but rather prospering.

For example, [there(1)][1] [are(2)][2] [still(3)][3] [many(4)][4] [answers(5)][5], including the [second most upvoted answer][6] suggesting you manual string escaping - an outdated approach that is proven to be insecure.

Or there is a slightly better answer that suggests just [another method of string formatting][7] and even boasts it as the ultimate panacea. While of course, it is not. This method is no better than regular string formatting, yet it keeps all its drawbacks: it is applicable to strings only and, like any other manual formatting, it's essentially optional, non-obligatory measure, prone to human error of any sort.

I think that all this because of one very old superstition, supported by such authorities like [OWASP][8] or [the PHP manual][9], which proclaims equality between whatever "escaping" and protection from SQL injections.

Regardless of what PHP manual said for ages, **`*_escape_string` by no means makes data safe** and never has been intended to. Besides being useless for any SQL part other than string, manual escaping is wrong, because it is manual as opposite to automated.

And OWASP makes it even worse, stressing on escaping *user input* which is an utter nonsense: there should be no such words in the context of injection protection. Every variable is potentially dangerous - no matter the source! Or, in other words - every variable has to be properly formatted to be put into a query - no matter the source again. It's the destination that matters. The moment a developer starts to separate the sheep from the goats (thinking whether some particular variable is "safe" or not) he/she takes his/her first step towards disaster. Not to mention that even the wording suggests bulk escaping at the entry point, resembling the very magic quotes feature - already despised, deprecated and removed.

So, unlike whatever "escaping", prepared statements *is* the measure that indeed protects from SQL injection (when applicable).

[1]:

[To see links please register here]

[2]:

[To see links please register here]

[3]:

[To see links please register here]

[4]:

[To see links please register here]

[5]:

[To see links please register here]

[6]:

[To see links please register here]

[7]:

[To see links please register here]

[8]:

[To see links please register here]

[9]:

[To see links please register here]


Reply

#18
There are many ways of preventing SQL injections and other SQL hacks. You can easily find it on the Internet (Google Search). Of course **PDO is one of the good solutions.** But I would like to suggest you some good links prevention from SQL injection.

*[What is SQL injection and how to prevent][1]*

*[PHP manual for SQL injection][2]*

*[Microsoft explanation of SQL injection and prevention in PHP][3]*

And some other like *[Preventing SQL injection with MySQL and PHP][4]*.

Now, **why you do you need to prevent your query from SQL injection?**

I would like to let you know: Why do we try for preventing SQL injection with a short example below:

Query for login authentication match:

$query="select * from users where email='".$_POST['email']."' and password='".$_POST['password']."' ";

Now, if someone (a hacker) puts

$_POST['email']= [email protected]' OR '1=1
and password anything....

The query will be parsed into the system only up to:

$query="select * from users where email='[email protected]' OR '1=1';

The other part will be discarded. So, what will happen? A non-authorized user (hacker) will be able to log in as administrator without having his/her password. Now, he/she can do anything that the administrator/email person can do. See, it's very dangerous if SQL injection is not prevented.

[1]:

[To see links please register here]

[2]:

[To see links please register here]

[3]:

[To see links please register here]

[4]:

[To see links please register here]

Reply

#19
A good idea is to use an [object-relational mapper][1] like [Idiorm][2]:

$user = ORM::for_table('user')
->where_equal('username', 'j4mie')
->find_one();

$user->first_name = 'Jamie';
$user->save();

$tweets = ORM::for_table('tweet')
->select('tweet.*')
->join('user', array(
'user.id', '=', 'tweet.user_id'
))
->where_equal('user.username', 'j4mie')
->find_many();

foreach ($tweets as $tweet) {
echo $tweet->text;
}

It not only saves you from SQL injections, but from syntax errors too! It also supports collections of models with method chaining to filter or apply actions to multiple results at once and multiple connections.

[1]:

[To see links please register here]

[2]:

[To see links please register here]



Reply

#20
As you can see, people suggest you use prepared statements at the most. It's not wrong, but when your query is executed **just once** per process, there would be a slight performance penalty.

I was facing this issue, but I think I solved it in *very* sophisticated way - the way hackers use to avoid using quotes. I used this in conjunction with emulated prepared statements. I use it to prevent *all* kinds of possible SQL injection attacks.

## My approach:

- If you expect input to be integer make sure it's ***really*** integer. In a variable-type language like PHP it is this *very* important. You can use for example this very simple but powerful solution: `sprintf("SELECT 1,2,3 FROM table WHERE 4 = %u", $input);`

- If you expect anything else from integer **hex it**. If you hex it, you will perfectly escape all input. In C/C++ there's a function called [`mysql_hex_string()`][1], in PHP you can use [`bin2hex()`][2].

Don't worry about that the escaped string will have a 2x size of its original length because even if you use `mysql_real_escape_string`, PHP has to allocate same capacity `((2*input_length)+1)`, which is the same.

- This hex method is often used when you transfer binary data, but I see no reason why not use it on all data to prevent SQL injection attacks. Note that you have to prepend data with `0x` or use the MySQL function `UNHEX` instead.

So, for example, the query:

SELECT password FROM users WHERE name = 'root';

Will become:

SELECT password FROM users WHERE name = 0x726f6f74;

or

SELECT password FROM users WHERE name = UNHEX('726f6f74');

Hex is the perfect escape. No way to inject.

## Difference between UNHEX function and 0x prefix

There was some discussion in comments, so I finally want to make it clear. These two approaches are very similar, but they are a little different in some ways:

The `0x` prefix can only be used for data columns such as `char`, `varchar`, `text`, `block`, `binary`, etc.
Also, its use is a little complicated if you are about to insert an empty string. You'll have to entirely replace it with `''`, or you'll get an error.

`UNHEX()` works on **any** column; you do not have to worry about the empty string.

---

## Hex methods are often used as attacks

Note that this hex method is often used as an SQL injection attack where integers are just like strings and escaped just with `mysql_real_escape_string`. Then you can avoid the use of quotes.

For example, if you just do something like this:

"SELECT title FROM article WHERE id = " . mysql_real_escape_string($_GET["id"])

an attack can inject you very *easily*. Consider the following injected code returned from your script:

SELECT ... WHERE id = -1 UNION ALL SELECT table_name FROM information_schema.tables;

and now just extract table structure:

SELECT ... WHERE id = -1 UNION ALL SELECT column_name FROM information_schema.column WHERE table_name = __0x61727469636c65__;

And then just select whatever data ones want. Isn't it cool?

But if the coder of an injectable site would hex it, no injection would be possible because the query would look like this:

SELECT ... WHERE id = UNHEX('2d312075...3635');

[1]:

[To see links please register here]

[2]:

[To see links please register here]

Reply



Forum Jump:


Users browsing this thread:
1 Guest(s)

©0Day  2016 - 2023 | All Rights Reserved.  Made with    for the community. Connected through