目前我正在研究一个简单工具的概念,以执行用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
答案 0 :(得分:0)
你总是希望转义`标识符,甚至是表名和字段名,因为明天它们可能是保留字并打破你的查询。只要您使用预备语句(PDO,mysqli或其他),您就可以了。请注意,PDO不允许转义表或字段名称。
你只需要对你的过滤机制进行细化,关于允许和不使用什么表名等。
顺便说一句:不要像你想做的那样:“CREATE TABLE {$ quoted_table_name} LIKE {$ table_name}”; ..用户准备好的语句与占位符(?,或:名称等)
修改强> 由于您需要保护标识符,我看到两种方式:
答案 1 :(得分:-1)
正如您所提到的,PDO的quote()函数可用于转义列名和数据。或者使用诸如CREATE TABLE之类的预准备语句?喜欢 ?然后只需执行查询。