Technical realization of PHP+SQL injection attack and its prevention methods _php skills

Source: Internet
Author: User
Tags mysql functions mysql injection numeric value php script sql injection sql injection attack
Summarize the experience. In my opinion, the main reason for the SQL injection attack is due to the following two points:
1. The MAGIC_QUOTES_GPC option in the PHP configuration file php.ini is not turned on and is set to off
2. Developers do not check and escape data types
But in fact, the 2nd is the most important. I think that it is the most basic quality of a web programmer to check the data type entered by the user and submit the correct data type to MYSQL. But in reality, many small white Web developers often forget this, leading to a backdoor opening.
Why is the 2nd most important? Because without a 2nd guarantee, the MAGIC_QUOTES_GPC option, whether on or off, can trigger a SQL injection attack. Here's a look at the technology implementation:
A. MAGIC_QUOTES_GPC = injection attack at off
MAGIC_QUOTES_GPC = Off is a very unsafe option in PHP. The new version of PHP has changed the default value to ON. However, there are still a considerable number of servers with the option off. After all, the antique server is also used by others.
When MAGIC_QUOTES_GPC = ON, it automatically adds \ to all the "(single quotes)," (double), \ (backslash), white-space characters in the submitted variable. The following is an official description of PHP:

Copy Code code as follows:

MAGIC_QUOTES_GPC Boolean

Sets the Magic_quotes State for GPC (Get/post/cookie) operations. When magic_quotes are on, all ' (Single-quote), "(double quote), \ (backslash) and NUL ' s are escaped with a backslash aut Omatically

If there is no escape, that is, off the case, the attacker can take advantage. Take the following test script as an example:
Copy Code code as follows:

?
if (Isset ($_post["F_login"]))
{
Connect database ...
// ... Code slightly ...

Check if the user exists
$t _struname = $_post["F_uname"];
$t _strpwd = $_post["F_pwd"];
$t _strsql = "SELECT * from tbl_users WHERE username= ' $t _struname ' and password = ' $t _strpwd ' LIMIT 0,1";

if ($t _hres = mysql_query ($t _strsql))
{
Processing after a successful query. Slightly...
}
}
?>

<body>
<form method=post action= "" >
Username: <input type= "text" name= "F_uname" size=30><br>
Password: <input type=text name= "F_pwd" size=30><br>

<input type= "Submit" Name= "F_login" value= "Login" >
</form>
</body>

In this script, when the user enters a normal username and password, assuming the value is Zhang3, abc123, the submitted SQL statement is as follows:
Copy Code code as follows:

SELECT * from Tbl_users
WHERE username= ' zhang3 ' and password = ' abc123 ' LIMIT

If an attacker enters the Zhang3 ' OR 1=1 # in the Username field and enters abc123 in password, the submitted SQL statement becomes the following:
Copy Code code as follows:

SELECT * from Tbl_users
WHERE username= ' Zhang3 ' OR 1=1 # ' and password = ' abc123 ' LIMIT 0,1

Because # is the annotation character in MySQL, #之后的语句不被执行, the implementation of this line statement becomes:
Copy Code code as follows:

SELECT * from Tbl_users
WHERE username= ' zhang3 ' OR 1=1

This will allow the attacker to bypass authentication. If the attacker knew the structure of the database, it would be more dangerous to build a UNION SELECT:

Suppose to enter in Username: Zhang3 ' OR 1 =1 UNION Select Cola, colb,cold from Tbl_b #

In Password input: abc123,

Then the submitted SQL statement becomes:
Copy Code code as follows:

SELECT * from Tbl_users
WHERE username= ' Zhang3 '

OR 1 =1 UNION Select Cola, colb,cold from Tbl_b # ' and password = ' abc123 ' LIMIT 0,1
This is quite dangerous. If the AGIC_QUOTES_GPC option is on and the quotation marks are escaped, then the attack statements built by the attacker above will become this way and cannot achieve their purpose:
Copy Code code as follows:

SELECT * from Tbl_users
WHERE username= ' zhang3\ ' OR 1=1 # '
and password = ' abc123 '
LIMIT 0,1

SELECT * from Tbl_users
WHERE username= ' zhang3 \ ' OR 1 =1 UNION Select Cola, colb,cold from Tbl_b # '
and password = ' abc123 ' LIMIT 0,1

Two. MAGIC_QUOTES_GPC = injection attack on
When MAGIC_QUOTES_GPC = ON, an attacker cannot inject SQL into a character-type field. That doesn't mean it's safe. In this case, you can use the numeric fields for SQL injection.

In the latest version of MYSQL 5.x, the data type has been strictly entered, and automatic type conversion has been turned off by default. A field of numeric type, which cannot be a character type that is quoted as a quotation mark. In other words, suppose the UID is numeric, and in previous versions of MySQL, such statements were legal:
Copy Code code as follows:

INSERT into Tbl_user SET uid= "1";
SELECT * from Tbl_user WHERE uid= "1";

In the latest MYSQL 5.x, the above statement is not legal and must be written like this:
Copy Code code as follows:

INSERT into Tbl_user SET uid=1;
SELECT * from Tbl_user WHERE uid=1;

So I think it's right. Because as a developer, submitting the correct conforming data type to the database is the most basic requirement.

So how do attackers attack when MAGIC_QUOTES_GPC = on? The simple thing is to inject SQL into the field of a numeric type. Take the following PHP script as an example:
Copy Code code as follows:

?
if (Isset ($_post["F_login"]))
{
Connect database ...
// ... Code slightly ...

Check if the user exists
$t _struid = $_post["F_uid"];
$t _strpwd = $_post["F_pwd"];
$t _strsql = "SELECT * from Tbl_users WHERE uid= $t _struid and password = ' $t _strpwd ' LIMIT 0,1 ';
if ($t _hres = mysql_query ($t _strsql))
{
Processing after a successful query. Slightly...
}

}
?>
<body>
<form method=post action= "" >
User ID: <input type= "text" name= "F_uid" size=30><br>

Password: <input type=text name= "F_pwd" size=30><br>
<input type= "Submit" Name= "F_login" value= "Login" >
</form>
</body>


The above script requires the user to enter UserID and password login. A normal statement, the user enters 1001 and abc123, submits the SQL statement as follows:

SELECT * from tbl_users WHERE userid=1001 and password = ' abc123 ' LIMIT 0,1
If the attacker is at UserID, enter: 1001 OR 1 = 1 #, the injected SQL statement is as follows:

SELECT * from Tbl_users WHERE userid=1001 OR 1 =1 # and password = ' abc123 ' LIMIT 0,1
The attackers achieved their purpose.

Three. How to prevent PHP SQL injection attacks
How do I prevent PHP SQL injection attacks? I think the most important thing is to check and escape the data type. Some of the rules summarized are as follows:

The display_errors option in php.ini should be set to Display_errors = off. This way, the PHP script does not output errors on the Web page, so that the attacker can parse out the information.
When calling MySQL functions such as mysql_query, you should precede the @, that is @mysql_query (...), so that the MySQL error will not be output. In the same vein, the attacker is not allowed to analyze useful information. In addition, some programmers in development, when mysql_query error, custom output errors and SQL statements, such as:
Copy Code code as follows:

$t _strsql = "Select a from B ...";
if (mysql_query ($t _strsql))
{
The right treatment
}
Else
{
echo "Error! SQL statement: $t _strsql \ r \ n error message ". mysql_query ();
Exit
}

This practice is quite dangerous and stupid. If you do this, it's a good idea to set a global variable or define a macro in your site's configuration file to set the debug flag:

Global configuration file:
Copy Code code as follows:

Define ("Debug_mode", 0); 1:debug MODE; 0:release MODE

In the calling script:
$t _strsql = "Select a from B ...";
if (mysql_query ($t _strsql))
{
The right treatment
}
Else
{
if (Debug_mode)
echo "Error! SQL statement: $t _strsql \ r \ n error message ". mysql_query ();
Exit
}

An escape and type check for the submitted SQL statement.
Four. I write a security parameter get function
To prevent user error data and PHP + MySQL injection, I wrote a function papi_getsafeparam () to get the safe parameter values:
Copy Code code as follows:

Define ("Xh_param_int", 0);
Define ("Xh_param_txt", 1);
function Papi_getsafeparam ($pi _strname, $pi _def = "", $pi _itype = xh_param_txt)
{
if (Isset ($_get[$pi _strname]))
$t _val = Trim ($_get[$pi _strname]);
else if (isset ($_post[$pi _strname]))
$t _val = Trim ($_post[$pi _strname]);
Else
return $PI _def;

Int
if (Xh_param_int = = $pi _itype)
{
if (Is_numeric ($t _val))
return $t _val;
Else
return $PI _def;
}

String
$t _val = Str_replace ("&", "&", $t _val);
$t _val = Str_replace ("<", "<", $t _val);
$t _val = Str_replace (">", ">", $t _val);
if (GET_MAGIC_QUOTES_GPC ())
{
$t _val = Str_replace ("\\\" "," "" ", $t _val);
$t _val = str_replace ("\" "," "", $t _val);
}
Else
{
$t _val = str_replace ("\" "," "", $t _val);
$t _val = Str_replace ("'", "'", $t _val);
}
return $t _val;
}

In this function, there are three parameters:

$PI _strname: Variable name
$PI _def: Default value
$PI _itype: Data type. The value is Xh_param_int, Xh_param_txt, representing the numeric and textual types respectively.
If the request is a numeric type, then call Is_numeric () to determine whether it is a numeric value. If it is not, the default value specified by the program is returned.

For simplicity, for a text string, I escape all the dangerous characters (including the HTML code) that the user enters. Because the PHP function addslashes () there is a vulnerability, I use Str_replace () directly replace. The GET_MAGIC_QUOTES_GPC () function is a PHP function that is used to determine whether the MAGIC_QUOTES_GPC option is open.


For the example in the second section, the code can call this:
Copy Code code as follows:

?
if (Isset ($_post["F_login"]))
{
Connect database ...
// ... Code slightly ...

Check if the user exists
$t _struid = Papi_getsafeparam ("F_uid", 0, Xh_param_int);
$t _strpwd = Papi_getsafeparam ("F_pwd", "", xh_param_txt);
$t _strsql = "SELECT * from Tbl_users WHERE uid= $t _struid and password = ' $t _strpwd ' LIMIT 0,1 ';
if ($t _hres = mysql_query ($t _strsql))
{
Processing after a successful query. Slightly...
}
}
?>

In that case, it would have been quite safe. Papi_getsafeparam's code is a bit long, but sacrificing this efficiency is worth the security. I hope you will criticize me more. :)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.