如果您通过网页输入用户输入并将其插入到SQL数据库中,则可能会遇到因 SQL注入而引起的安全问题。本章将教您如何防止这种情况的发生,并帮助您保护服务器端脚本(如PERL脚本)中的脚本和SQL语句。
在下面的示例中,名称限于字母数字字符加下划线,并且长度介于8到20个字符之间(根据需要修改这些规则)。
if (preg_match("/^\w{8,20}$/", $_GET['username'], $matches)) { $result=mysql_query("SELECT * FROM CUSTOMERS WHERE name=$matches[0]"); } else { echo "user name not accepted"; }
为了演示问题,请考虑以下摘录-
//supposed input $name="Qadir'; DELETE FROM CUSTOMERS;"; mysql_query("SELECT * FROM CUSTOMSRS WHERE name='{$name}'");
该函数调用应该从CUSTOMERS表中检索一条记录,其中name列与用户指定的名称匹配。在正常情况下, $name 仅包含字母数字字符,可能还包含空格,如字符串ilia。但是在这里,通过在$name后面附加一个全新的查询,对数据库的调用变成了灾难,注入的DELETE查询将从CUSTOMERS表中删除所有记录。
幸运的是,如果使用MySQL,则 mysql_query()函数不允许查询堆栈或在单个函数调用中执行多个SQL查询,如果您尝试堆叠查询,则调用将失败。
但是,其他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 CUSTOMERS WHERE name='{$name}'");
LIKE 语句
为了解决LIKE难题,自定义转义机制必须将用户提供的'%'和'_'字符转换为文字。使用 addcslashes(),该函数可让您指定要转义的字符范围。
$sub=addcslashes(mysql_real_escape_string("%str"), "%_"); //$sub ==\%str\_ mysql_query("SELECT * FROM messages WHERE subject LIKE '{$sub}%'");