One is to filter the input data (filter input), and one is to not escape the data sent to the database (escape output). These two important steps are indispensable and require special attention at the same time to reduce procedural errors.
For an attacker to think and experiment with a SQL injection attack, it is necessary to have a well-founded reasoning for the database scenario (assuming, of course, that the attacker does not see your source and database scenarios), consider the following simple login form:
Copy Code code as follows:
<form action= "/login.php" method= "POST" >
<p>username: <input type= "text" name= "Username"/></p>
<p>password: <input type= "Password" name= "Password"/></p>
<p><input type= "Submit" value= "Log in"/></p>
</form>
As an attacker, he starts with a query that speculates to verify the username and password. By looking at the source file, he can begin to guess your habits.
Like naming habits. It is usually assumed that the field name in your form is the same as the field name in the datasheet. Of course, ensuring that they are different is not necessarily a reliable security measure.
For the first time, you will typically use the query in the following example:
Copy Code code as follows:
<?php
$password _hash = MD5 ($_post[' password '));
$sql = "SELECT count (*)
From users
WHERE username = ' {$_post[' username ']} '
and password = ' $password _hash ' ";
?>
Using the MD5 value of a user's password is a common practice, but it is not particularly safe now. Recent studies have shown that the MD5 algorithm is flawed, and a large number of MD5 databases reduce the difficulty of MD5 reverse cracking. Visit the http://md5.rednoize.com/to see the demo (in the original case, the study by Professor Wangxiaoyun of Shandong University shows that it is possible to quickly find the MD5 "collision", which can produce different two files and strings of the same MD5 value. MD5 is the information digest algorithm, not the encryption algorithm, reverse crack also can not talk about. However, according to this result, in the above special case, direct use of MD5 is dangerous. )。
The best way to protect your password is to attach a string of your own definition, such as:
Copy Code code as follows:
<?php
$salt = ' Shiflett ';
$password _hash = MD5 ($salt. MD5 ($_post[' password ']. $salt));
?>
Of course, attackers may not be able to guess the first time, they often need to do some experiments. One of the better ways to do this is to use single quotes as user names because it may expose some important information. Many developers call function mysql_error () to report errors when the MySQL statement executes incorrectly. See the following example:
Copy Code code as follows:
<?php
mysql_query ($sql) or exit (Mysql_error ());
?>
Although this method is useful in development, it can expose important information to attackers. If an attacker makes a single quote as a username and mypass as a password, the query statement becomes:
Copy Code code as follows:
<?php
$sql = "SELECT *
From users
WHERE username = ' '
and password = ' a029d0df84eb5549c641e04a9ef389e5 ';
?>
When the statement is sent to MySQL, the system displays the following error message:
Copy Code code as follows:
You are have an error in your SQL syntax. Check the manual that corresponds to your
MySQL Server version for the right syntax to use near ' WHERE username = ' and
Password = ' a029d0df84eb55
Effortlessly, the attacker already knows the two field names (username and password) and the order in which they appear in the query. In addition, the attacker knew that the data was not properly filtered (the program did not prompt for an illegal user name) and escaped (a database error occurred) and that the entire where condition was exposed, so that the attacker could attempt to manipulate the records that matched the query.
At this point, the attackers have a lot of options. One is to try to fill in a special username so that the query can be matched regardless of whether the username or password is met:
Copy Code code as follows:
MyUser ' or ' foo ' = ' foo '-
Assuming the mypass as a password, the entire query becomes:
Copy Code code as follows:
<?php
$sql = "SELECT *
From users
WHERE username = ' myuser ' or ' foo ' = ' foo '--
and password = ' a029d0df84eb5549c641e04a9ef389e5 ';
?>
Fortunately, SQL injection is easy to avoid. As mentioned earlier, you must persist in filtering input and escaping output.
Although none of the two steps can be omitted, the implementation of one of these will eliminate most of the SQL injection risk. If you just filter input without escaping output, you are likely to experience database errors (legitimate data can also affect the correct format of SQL queries), but this is also unreliable, and legitimate data can also alter the behavior of SQL statements. On the other hand, if you escape the output without filtering the input, you can guarantee that the data does not affect the format of the SQL statement, but also prevent multiple methods of common SQL injection attacks.
Of course, stick with both of these steps. The way you filter the input depends entirely on the type of input data (see the example in Chapter one), but you can use the same function to escape the output data that is sent to the database. For MySQL users, you can use the function mysql_real_escape_string ():
Copy Code code as follows:
<?php
$clean = Array ();
$mysql = Array ();
$clean [' last_name '] = "O ' Reilly";
$mysql [' last_name '] = mysql_real_escape_string ($clean [' last_name ']);
$sql = "INSERT
into User (last_name)
VALUES (' {$mysql [' last_name ']} ');
?>
Try to use the escape function designed for your database. If not, using the function addslashes () is the ultimate better approach.
When all the data used to establish an SQL statement is properly filtered and escaped, the risk of SQL injection is actually avoided. If you're using a database operation class that supports parameterized query statements and placeholders (such as pear::D B, PDO, etc.), you'll get a layer of protection. See the following examples of using pear::D B:
Copy Code code as follows:
<?php
$sql = ' INSERT
into User (last_name)
VALUES (?) ';
$DBH->query ($sql, Array ($clean [' last_name ']));
?>
Because the data in the previous example does not directly affect the format of the query statement, the risk of SQL injection is reduced. PEAR::D B will automatically escape according to your database requirements, so you just need to filter out the output.
If you are using a parameterized query, the input is processed only as data. There is no need to escape, although you may think that this is a necessary step (if you want to persist in escaping the output habit). In fact, it doesn't have an impact at this point because there are no special characters to convert. In preventing SQL injection, parameterized query statements provide powerful protection for your programs.
Note: With regard to SQL injection, it is necessary to say that most virtual hosts now turn on the MAGIC_QUOTES_GPC option, in which case all client get and post data will be addslashes processed automatically, so SQL injection of string values is not feasible at this time , but to prevent the SQL injection of numeric values, such as using functions such as intval () for processing. But if you write generic software, you need to read the server's MAGIC_QUOTES_GPC and do the processing accordingly.