如果您通过网页获取用户输入并将其插入SQL数据库,那么您可能会因为 SQL注入这样的安全问题而敞开大门.本章将教您如何帮助防止这种情况发生,并帮助您在服务器端脚本(如PERL脚本)中保护脚本和SQL语句.
当您询问时,通常会发生注入用户输入,就像他们的名字,而不是名称,他们给你一个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 )会愉快地执行堆栈查询,执行一个字符串中提供的所有查询并产生严重的安全问题.
您可以巧妙地处理所有转义字符在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窘境,自定义转义机制必须转换用户提供的'%'和'_'字符到文字.使用 addcslashes(),这个函数可以指定要转义的字符范围.
$sub = addcslashes(mysql_real_escape_string("%str"), "%_"); // $sub == \%str\_ mysql_query("SELECT * FROM messages WHERE subject LIKE '{$sub}%'");