没有绑定参数的mysqli准备好的语句仍然安全吗?

Posted

技术标签:

【中文标题】没有绑定参数的mysqli准备好的语句仍然安全吗?【英文标题】:mysqli prepared statement without binding parameters still secure? 【发布时间】:2013-01-07 12:28:08 【问题描述】:

这是我在这里的第一篇文章,而且我对编程世界也比较陌生。 简而言之,在结束我使用 phpmysqljavascript/jquery 开发的电子商务网站时,我发现我构建所有查询的方式(使用 mysql_connect)可能会导致 mysql 注入和许多其他讨厌的事情东西。

尝试将所有内容“转换”为更安全的 mysqli 准备语句方式,我编写了一个类,其中包含从数据库中检索信息所需的所有方法,但我不确定我的方式正在查询。

一些代码:类构造函数

class Database 

    private $DBH;

    public function __construct() 
        $this->DBH = new mysqli(WEB_SERVER, WEB_USER, WEB_PASS, WEB_NAME);
        if ($this->DBH->connect_errno) 
            return "Failed to connect to MySQL: (" . $this->DBH->connect_errno . ") " . $this->DBH->connect_error;
            exit();
        
    
    ...

...还有一个查询示例:

public function get_record_by_param($record, $param, $value) 
    $stmt = $this->getDBH()->stmt_init();

    $query = "SELECT * ";
    $query .= "FROM $record ";
    $query .= "WHERE $param = $value LIMIT 1";

    if($stmt->prepare($query))
        return $this->execute_simpleAssoc($stmt);
     else 
    return "Prepare failed: (" . $this->getDBH()->errno . ") " . $this->getDBH()->error;
    

使用这样的查询仍然安全吗? 还是我一定需要使用 bind_param 方法?

希望我没有混淆,感谢您的任何建议。

【问题讨论】:

不是它不是,是的,你这样做。但是您不能绑定$record 表名或$param 列名。这些应该与可接受值的白名单进行比较。在上面的示例中,只能绑定 $value +1 提问,这太重要了 【参考方案1】:

不,它不安全。 mysqli 无法解析查询字符串中的哪些是(可能易受攻击的)数据,哪些不是。

如果您希望数据转义,则需要分别绑定每个参数。

绑定参数仅适用于数据。对于列名,您需要应用@Michael 在他的评论中指出的白名单。无法自动转义列/表名。

这适用于所有 数据库层,包括 PDO。如果您向图层提供完整的查询字符串,则其中的数据将不会被神奇地转义。

【讨论】:

我有点期待这个答案,但是.. 我该如何做这个“白名单”的事情?你能告诉我在哪里可以找到一些例子吗?我唯一想到的是进行另一个查询,验证提供的列/表名称是否已经在数据库中,但在更改所有内容之前我想更确定一点.. @piter 是的,没错,它就是这样工作的 - 找到所有列/表名,将它们放入一个数组中,然后对它们执行 in_array() 好的,我会尝试在这里发布结果。并感谢您“超快速”的回答!【参考方案2】:

嗯,这更像是一个术语问题。看,有

在查询中表示数据的占位符的一般概念 prepared statements,它是占位符的子集 绑定的东西,属于prepared statements,但可以省略

最有可能在“绑定”下您的意思是准备好的陈述。在这种情况下,答案可能会有所不同。 但是如果您采用占位符的想法,答案就会改变: 当然,您运行查询的方式仍然不安全。 但是,没有(手动)绑定也可以进行完全安全的查询。 因此,不需要 bind_param。

【讨论】:

以上是关于没有绑定参数的mysqli准备好的语句仍然安全吗?的主要内容,如果未能解决你的问题,请参考以下文章

MySQLi准备好的语句不绑定整数

mySqli 使用通配符绑定参数 LIKE

带有变量的Mysqli准备好的语句列[重复]

mysqli 使用 select * 和准备好的语句和查询

mysqli_stmt::bind_result():绑定变量的数量与准备好的语句中的字段数量不匹配

我可以重新定义相同的准备好的语句吗?