MySQL - 和SQL注入

如果您通过网页接收用户输入并将其插入MySQL数据库,那么您可能会因为称为 SQL注入的安全问题而敞开大门.本章将教您如何帮助防止这种情况发生并帮助您保护脚本和MySQL语句.

当您向用户询问输入时,通常会发生SQL注入,例如他们的名字和而不是名称,他们会给你一个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}'");

函数调用应该从users表中检索记录,其中name列与用户指定的名称匹配.在正常情况下,$ name只包含字母数字字符和空格.但是在这里,通过向 $ name 添加一个全新的查询,对数据库的调用将变成灾难.注入的DELETE查询会删除用户的所有记录.

幸运的是,如果使用MySQL, mysql_query()函数不允许查询堆栈或执行多个查询在单个函数调用中.如果您尝试堆栈查询,则调用失败.

然而,其他PHP数据库扩展,例如 SQLite PostgreSQL ,很高兴执行堆栈查询,执行一个字符串中提供的所有查询并创建严重的安全问题.

防止SQL注入

您可以处理所有转义字符巧妙地使用PERL和PHP等脚本语言. PHP的MySQL扩展提供函数 mysql_real_escape_string()来转义MySQL特有的输入字符.

if (get_magic_quotes_gpc()) {
   $name = stripslashes($name);
}

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

LIKE Quandary

要解决LIKE窘境,自定义转义机制必须转换用户提供的%和_字符到文字.使用 addcslashes(),这个函数可以指定要转义的字符范围.

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