PHP开发教程

MySQL SQL注入

如果通过网页需要用户输入一些数据信息,并将其插入到MySQL数据库,这是一个引入SQL注入安全问题的机会。这一节将学习如何防止这种情况的发生,并帮助保护脚本和MySQL语句。

通常注入是在当要求用户输入时,类似他们的姓名,只是一个名字,他们给出,会在不知不觉中包含MySQL的语句会在数据库运行。

永远不要信任用户提供的数据,这个过程只有在数据验证后,作为一项规则,这是通过模式匹配进行。在下面的例子中,用户名被限制在字母+数字+字符加下划线,并在8-20个字符之间的长度 - 可以根据需要修改这些规则。

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

为了说明问题,考虑这个片段:

// supposed input
$name = "Qadir'; DELETE FROM users;";
mysql_query("SELECT * FROM users WHERE name='{$name}'");

该函数调用从表中检索用户记录,其中名称列匹配由用户指定的名称。 在正常情况下,$name将只包含字母数字字符,或可能是空格,如字符串ilia。 但在这里,通过附加一个全新的查询到$name,在调用数据库变成灾难:注入DELETE查询删除所有的用户记录。

幸运的是,如果使用MySQL,mysql_query()函数不允许查询堆叠或一个函数调用执行多个查询。如果尝试堆叠查询,调用失败。

然而,其他PHP数据库扩展,如SQLite和PostgreSQL,它们会乐意地进行堆查询,执行一个字符串提供的查询,并创建一个严重的安全问题。

防止SQL注入

可以在脚本语言,如 Perl和PHP巧妙地处理所有转义字符。MySQL扩展为PHP提供mysql_real_escape_string()函数来转义输入的特殊字符。

if (get_magic_quotes_gpc()) 
{
  $name = stripslashes($name);
}
$name = mysql_real_escape_string($name);
mysql_query("SELECT * FROM users WHERE name='{$name}'");

LIKE的困境

为了解决LIKE困境,自定义的转义机制必须把用户提供%和_字符到常量。使用addcslashes()函数,它可以让指定的字符转义。

$sub = addcslashes(mysql_real_escape_string("%something_"), "%_");
// $sub == \%something\_
mysql_query("SELECT * FROM messages WHERE subject LIKE '{$sub}%'");


Powered by PHP二次开发 ©2008-2017