在这个脚本中,当用户输入正常的用户名和密码,假设值分别为 zhang3、abc123,则提交的 SQL 语句如下:
  SELECT * FROM tbl_users WHERE username='zhang3' AND password = 'abc123' LIMIT 0,1
  如果攻击者在 username 字段中输入:zhang3' OR 1=1 #,在 password 输入 abc123,则提交的 SQL 语句变成如下:
  SELECT * FROM tbl_users WHERE username='zhang3' OR 1=1 #' AND password = 'abc123' LIMIT 0,1
  由于 # 是 mysql中的注释符, #之后的语句不被执行,实现上这行语句成了:
  SELECT * FROM tbl_users WHERE username='zhang3' OR 1=1
  这样攻击者可以绕过认证了。如果攻击者知道数据库结构,那么它构建一个 UNION SELECT,那更危险了:
  假设在 username 中输入:zhang3 ' OR 1 =1 UNION select cola, colb,cold FROM tbl_b #
  在password 输入: abc123,
  则提交的 SQL 语句变成:
  SELECT * FROM tbl_users WHERE username='zhang3 ' OR 1 =1 UNION select cola, colb,cold FROM tbl_b #' AND password = 'abc123' LIMIT 0,1
  这样相当危险了。
  二、magic_quotes_gpc = On 时的注入攻击
  当 magic_quotes_gpc = On 时,攻击者无法对字符型的字段进行 SQL 注入。这并不代表这安全了。这时,可以通过数值型的字段进行SQL注入。
  在新版的 MYSQL 5.x 中,已经严格了数据类型的输入,已默认关闭自动类型转换。数值型的字段,不能是引号标记的字符型。也是说,假设 uid 是数值型的,在以前的 mysql 版本中,这样的语句是合法的:
  INSERT INTO tbl_user SET uid="1";
  SELECT * FROM tbl_user WHERE uid="1";
  在新的 MYSQL 5.x 中,上面的语句不是合法的,必须写成这样:
  INSERT INTO tbl_user SET uid=1;
  SELECT * FROM tbl_user WHERE uid=1;
  这样我认为是正确的。因为作为开发者,向数据库提交正确的符合规则的数据类型,这是基本的要求。
  那么攻击者在 magic_quotes_gpc = On 时,他们怎么攻击呢?很简单,是对数值型的字段进行 SQL 注入。以下列的 php 脚本为例:
<?
if (isset($_POST["f_login"])) {
// 连接数据库...
// ...代码略...
// 检查用户是否存在
$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)) {
// 成功查询之后的处理. 略...
}
}
?>
<html><head><title>test</title></head>
<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="登录">
</form>
</body>
</html>
  上面这段脚本要求用户输入 userid 和 password 登入。一个正常的语句,用户输入 1001和abc123,提交的 sql 语句如下:
  SELECT * FROM tbl_users WHERE userid=1001 AND password = 'abc123' LIMIT 0,1
  如果攻击者在 userid 处,输入:1001 OR 1 =1 #,则注入的sql语句如下:
  SELECT * FROM tbl_users WHERE userid=1001 OR 1 =1 # AND password = 'abc123' LIMIT 0,1
  攻击者达到了目的。

  三、如何防止 PHP的SQL 注入攻击
  如何防止 php sql 注入攻击?我认为重要的一点,是要对数据类型进行检查和转义。总结的几点规则如下:
  1. php.ini 中的 display_errors 选项,应该设为 display_errors = off。这样 php 脚本出错之后,不会在 web 页面输出错误,以免让攻击者分析出有作的信息。
  2. 调用 mysql_query 等 mysql 函数时,前面应该加上 @,即 @mysql_query(...),这样 mysql 错误不会被输出。同理以免让攻击者分析出有用的信息。另外,有些程序员在做开发时,当 mysql_query出错时,习惯输出错误以及 sql 语句,例如:
<php
$t_strSQL = "SELECT a from b....";
if (mysql_query($t_strSQL)) {
// 正确的处理
} else {
echo "错误! SQL 语句:$t_strSQL
错误信息" . mysql_query();
exit;
}
?>