SQL - 注入

  • 简述

    如果您通过网页获取用户输入并将其插入 SQL 数据库,那么您可能会因安全问题(称为SQL Injection. 本章将教您如何帮助防止这种情况发生,并帮助您保护服务器端脚本(如 PERL 脚本)中的脚本和 SQL 语句。
    当您要求用户输入时,通常会发生注入,例如他们的姓名,而不是姓名,他们会为您提供一条 SQL 语句,您将在不知不觉中在您的数据库上运行该语句。永远不要相信用户提供的数据,只有在验证后才处理这些数据;通常,这是由Pattern Matching.
    在下面的示例中,name限制为字母数字字符加下划线,长度在 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将只包含字母数字字符和可能的空格,例如字符串 ilia。但是在这里,通过向 $name 附加一个全新的查询,对数据库的调用变成了灾难;注入的 DELETE 查询从 CUSTOMERS 表中删除所有记录。
    幸运的是,如果您使用 MySQL,mysql_query()function 不允许查询堆叠或在单个函数调用中执行多个 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);
    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}%'");