SQL 注入

Table of content


如果您通过网页获取用户输入并将其插入 SQL 数据库,则您可能存在一个名为SQL 注入的安全漏洞风险。本章将教您如何预防此问题,并帮助您保护服务器端脚本(例如 PERL 脚本)中的脚本和 SQL 语句的安全。

SQL 注入

SQL 注入是一种安全攻击,它利用数据库中的漏洞来执行恶意查询。这将允许攻击者访问敏感数据,篡改数据以及永久删除数据。

注入通常发生在您向用户索取输入(例如他们的姓名)时,他们提供的不是姓名,而是一个您会在不知情的情况下在数据库上运行的 SQL 语句。永远不要信任用户提供的数据,只有在验证后才能处理此数据;通常,这是通过模式匹配完成的。

示例

在下面的示例中,name 限制为字母数字字符加上下划线,长度在 8 到 20 个字符之间(您可以根据需要修改这些规则)。

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

为了演示这个问题,请考虑以下摘录:

// supposed input
$name = "Qadir'; DELETE FROM CUSTOMERS;";
mysqli_query("SELECT * FROM CUSTOMSRS WHERE name='{$name}'");

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

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

但是,其他 PHP 数据库扩展(例如SQLitePostgreSQL)会愉快地执行堆叠查询,执行一个字符串中提供的所有查询,并造成严重的安全问题。

防止 SQL 注入

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

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

LIKE 难题

为了解决 LIKE 难题,自定义转义机制必须将用户提供的 '%' 和 '_' 字符转换为字面量。使用addcslashes(),这是一个允许您指定要转义的字符范围的函数。

$sub = addcslashes(mysql_real_escape_string("%str"), "%_");
// $sub == \%str\_
mysqli_query("SELECT * FROM messages 
   WHERE subject LIKE '{$sub}%'");
广告