我可以在准备好的语句中参数化表名吗?

Posted

技术标签:

【中文标题】我可以在准备好的语句中参数化表名吗?【英文标题】:Can I parameterize the table name in a prepared statement? 【发布时间】:2012-07-03 23:49:27 【问题描述】:

我已经多次使用 mysqli_stmt_bind_param 函数。但是,如果我将试图防止 SQL 注入的变量分开,我会遇到错误。

这是一些代码示例:

function insertRow( $db, $mysqli, $new_table, $Partner, $Merchant, $ips, $score, $category, $overall, $protocol )

    $statement = $mysqli->prepare("INSERT INTO " .$new_table . " VALUES (?,?,?,?,?,?,?);");
    mysqli_stmt_bind_param( $statment, 'sssisss', $Partner, $Merchant, $ips, $score, $category, $overall, $protocol );
    $statement->execute();

是否可以以某种方式将.$new_table. 连接替换为另一个问号语句、创建另一个绑定参数语句或添加到现有语句以防止 SQL 注入?

像这样或这样的某种形式:

function insertRow( $db, $mysqli, $new_table, $Partner, $Merchant, $ips, $score, $category, $overall, $protocol )
    
    $statement = $mysqli->prepare("INSERT INTO (?) VALUES (?,?,?,?,?,?,?);");
    mysqli_stmt_bind_param( $statment, 'ssssisss', $new_table, $Partner, $Merchant, $ips, $score, $category, $overall, $protocol );
    $statement->execute();

【问题讨论】:

不,参数化查询不只是将参数值放入查询字符串中,它还分别为 RDBMS 提供参数化查询和参数。但是这样的查询不能有表名或字段名作为参数。这样做的唯一方法是将表名动态编码到查询字符串中,就像您已经完成的那样。如果此字符串可能受到攻击,则应首先对其进行验证;例如针对允许表的白名单。 使用mysqli扩展是安全的,加油!但是不要忘记清理和验证所有字符串。如果表或字段名称或任何与您的数据库相对的名称! 您喜欢用什么特殊功能来消毒? @user1475765 在您的表名上使用转义函数并不能保护您免受任何侵害,请使用白名单。 Can php PDO Statements accept the table name as parameter? 的可能重复项 【参考方案1】:

您的问题的简短回答是“否”。

在最严格的意义上,在数据库级别,准备好的语句只允许为 SQL 语句的“值”位绑定参数。

对此的一种思考方式是“可以在语句的运行时执行时替换而不改变其含义的事物”。表名不是那些运行时值之一,因为它决定了 SQL 语句本身的有效性(即,哪些列名是有效的)并且在执行时更改它可能会改变 SQL 语句是否有效。

在稍高的级别上,即使在模拟准备好的语句参数替换而不是实际将准备好的语句发送到数据库的数据库接口中,例如 PDO,这可能允许您在任何地方使用占位符(因为占位符之前被替换被发送到这些系统中的数据库),表占位符的值将是一个字符串,并包含在发送到数据库的 SQL 中,因此 SELECT * FROM ?mytable 作为参数实际上最终会发送 @ 987654323@到数据库,这是无效的SQL。

你最好的选择就是继续

SELECT * FROM $mytable

但是如果$mytable 来自用户输入,您绝对应该有一个您首先检查的表的白名单。

【讨论】:

很好的建议,但根据我的经验,这不适用于更大的动态网站。如果您的网站具有多用户设置、大量且不断更新的库存等,则此解决方案将非常难以应用。 网站大小与表的数量以及知道最终用户可以通过参数直接查询哪些表几乎没有关系。归根结底,这是一个奇怪的网站,让最终用户首先做到这一点。【参考方案2】:

在尝试创建“数据库”时适用相同的规则。

您不能使用准备好的语句来绑定数据库。

即:

CREATE DATABASE IF NOT EXISTS ?

不会工作。请改用安全列表。

【讨论】:

以上是关于我可以在准备好的语句中参数化表名吗?的主要内容,如果未能解决你的问题,请参考以下文章

在 sqlplus 输入文件中参数化表名

为游标绑定变量参数化表名

如何保护带有参数化表名的查询不被注入

SQL Server 动态行转列(参数化表名分组列行转列字段字段值)

SQL Server 动态行转列(参数化表名分组列行转列字段字段值)

SQL Server 动态行转列(参数化表名分组列行转列字段字段值)