此函数是否适用于一般清理数据库查询变量?

Would this function work for generally sanitizing db query variables?

提问人:adrianTNT 提问时间:11/26/2022 更新时间:11/26/2022 访问量:88

问:

我知道大多数人都说只使用准备好的语句,但我有一个网站,里面有很多现有的查询,我需要通过函数方法清理变量。mysqli_real_escape_string()

此外,说的php手册是一个可以接受的替代方案,所以我在这里......mysqli_query()mysqli_real_escape_string()

我想做这种类型的查询:

$query = sprintf("SELECT * FROM users WHERE user_name = %s", 
                    query_var($user_name, "text"));
$Records = mysqli_query($db, $query) or die(mysqli_error($db));

我想知道以下功能是否有效,我不确定:

  • 我还应该在开始时做吗?我在 Adobe Dreamweaver 中使用的一个旧函数可以做到这一点。stripslashes()
  • 是否可以在后面添加引号?$the_value = "'".$the_value."'";mysqli_real_escape_string()
  • 它有什么明显/大的缺陷吗?

我注意到删除了多个并将其替换为一个,因此 migt 不能很好地用于一般用途,例如,当用户提交可能包含的文本注释或项目描述时,通常可以不在这里使用吗?stripslashes()\\\\\\\\\\stripslashes()

我最担心的是SQL注入,如果提交的数据包含html标签是可以的,因此,我在输出/打印数据时会处理这个问题。


if(!function_exists('query_var')){
    function query_var($the_value, $the_type="text"){
        
        global $db;
        
        // do I still need this ?
        // $the_value = stripslashes($the_value);
        
        $the_value = mysqli_real_escape_string($db, $the_value);
        
        // do not allow dummy type of variables
        if(!in_array($the_type, array('text', 'int', 'float', 'double'))){
            $the_type='text';
        }
        
        if($the_type=='text'){
            $the_value = "'".$the_value."'";
        } 
        
        if($the_type=='int'){
            $the_value = intval($the_value);
        }
         
        if($the_type == 'float' or $the_type=='double'){
            $the_value = floatval($the_value);
        } 
        
        return $the_value;
        
    }
}
php mysql 安全性 sql 注入 清理

评论

0赞 Bill Karwin 11/26/2022
如果您担心 SQL 注入,为什么不使用查询参数绑定?它更简单、更安全,您无需询问您的功能是否足够。您不需要函数。
0赞 adrianTNT 11/26/2022
因为该站点有超过 1000 个查询,每个查询有 4-5 行。我不能全部重写它们,它们已经包含一个清理变量的函数,我只需要修复该函数以处理现有的查询。我也不觉得 PDO 方式的可读性很强,它宣传变量及其类型的方式。也许对于一个新网站,我会使用 PDO。sprintf()
0赞 Bill Karwin 11/26/2022
您不必使用该类型。在MySQL PDO驱动程序中,无论如何,它们都绑定为字符串。您只需将数组传递给函数即可。execute()
0赞 adrianTNT 11/26/2022
变量类型必须有一个目的,我想这与我没有测试PDO是不同的。x > 10x > '10'
1赞 Bill Karwin 11/26/2022
我要说的是,我将代码转换为使用 PDO,并重写查询以使用参数。即使有 1000+ 查询,老实说,与担心清理功能的安全性相比,这并不是那么多工作。如果这需要两周的专注工作,我会感到惊讶。

答:

0赞 O. Jones 11/26/2022 #1

MySQL / MariaDB中的文本字符串常量以单引号字符开头和结尾。如果文本本身包含引号字符,我们可以通过将其加倍来转义它。因此,名称“O'Leary”在 SQL 语句的文本中如下所示。'

SET surname = 'O''Leary'

这是唯一的规则。如果您的用户使用反斜杠或其他转义方案为您提供数据,您可以使用此处提到的文本字符串表示形式逐字将其提供给 MySql。

不要想太多。但使用仔细调试的转义函数。避免编写自己的错误,因为任何微小的错误都允许 SQL 注入。

评论

0赞 adrianTNT 11/26/2022
你是说那里?我仍然不确定我是否应该这样做。SET surname = 'O\'Leary'stripslashesmysqli_real_escape_string
0赞 O. Jones 11/26/2022
我的意思是将单引号加倍。MySql 字符串常量中的反斜杠只是反斜杠。
0赞 adrianTNT 11/26/2022
现在我更困惑了:/两者都被接受并做同样的事情吗?当我从phpMyAdmin插入一个值时,它会将查询设置为这个,并且它起作用:''\'O'LearyINSERT INTO 'test' ('name') VALUES ('O\'Leary');
0赞 adrianTNT 11/26/2022 #2

查看PHP函数文档,我发现了一些参考资料,使我决定该函数中不需要这些函数。stripslashes()

https://www.php.net/manual/en/security.database.sql-injection.php

像 addslashes() 这样的泛型函数仅在非常特定的 环境(例如,单字节字符集中的 MySQL 禁用了 NO_BACKSLASH_ESCAPES)所以最好避免它们。

https://www.php.net/manual/en/function.addslashes.php

addslashes() 有时被错误地用于尝试阻止 SQL 注射。取而代之的是特定于数据库的转义函数和/或 应使用准备好的语句。