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}'");
该函数调用应该从用户表中检索一条记录,其中名称列与用户指定的名称匹配。在正常情况下,$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}'");
The LIKE困境
为了解决LIKE困境,必须使用自定义的转义机制将用户提供的%和下划线字符转换为文本。使用 addcslashes() 函数,该函数允许您指定要转义的字符范围。
$sub = addcslashes(mysql_real_escape_string("%something_"), "%_");
// $sub == \%something\_
mysql_query("SELECT * FROM messages WHERE subject LIKE '{$sub}%'");