【发布时间】:2016-06-16 16:56:52
【问题描述】:
目前我正在研究一个简单工具的概念,以执行一些用 PHP 编写的»维护«数据库操作(删除/截断/复制表等)。
这必然要求 SQL 语句中的标识符是动态用户输入。虽然准备好的语句非常适合将 SQL 语句与任何比较值的用户输入分开,但它们并不意味着用于表或列名等标识符。 (也就是说,我can't use准备了语句来准备标识符。)
保护动态标识符的常用方法是列入白名单,但这需要静态且已知的数据库结构。例如,我想实现一个类似Copy table A and name it B 的命令。这里有趣的部分是B。
假设用户已通过身份验证并允许执行此操作,我该如何保护它免受 SQL 注入?这可能吗?
我发现 an approach 建议在任何标识符中简单地引用重音符号 (`),如下所示:
$table_name = 'origin_table'; // can be checked against existing tables
$copy_table_name = 'user_input';
$quoted_table_name = '`' . str_replace( '`', '``', $copy_table_name ) . '`';
$sql_statement = "CREATE TABLE {$quoted_table_name} LIKE {$table_name}";
这是否足以防止可能的 SQL 注入?
更新
PDO::quote()(在答案中提到)不是一个选项。它不会转义重音 (`):
$user_input = 'table`; TRUNCATE TABLE users --';
var_dump( $pdo->quote( $user_input ) );
//string(33) "'table`; TRUNCATE TABLE users --'"
更新 2 PostgreSQL 扩展有一个功能就是为了这个目的:https://secure.php.net/manual/en/function.pg-escape-identifier.php
【问题讨论】:
-
是的,但只要将完整的字符串视为标识符,MySQL 就不会解释像
CHAR(96)这样的函数。 (编辑:我回答的评论已被删除) -
大声思考:我会让用户在表单中输入表名和列名。现在,这些可以验证无意义的字符和代码。然后可以轻松地检查它们是否与
mysql data dictionary匹配。任何不匹配都会出错。我也会有一个表和/或列的“白名单”。从提供的信息生成所需的 SQL 是一项相当简单的任务。 IE。想到query builders? -
@RyanVincent 谢谢,我会处理这些问题。最佳解决方案是使用像
TableCopier::copyTables( $src, $dest )这样的方法。我当然可以对此方法写评论:«不要将未过滤的值传递给它!»。但这并不能保护它免于被使用并在野外造成 SQL 漏洞。 -
我误会了。表单的输入必须是有效的表名和列名,否则它们将与mysql data dictionary不匹配?
标签: php mysql sql-injection