2016-03-03 98 views
1

目前我正在研究一个简单工具的概念,以执行一些用PHP编写的“维护”数据库操作(drop/truncate/copy tables等)。PHP PDO:保护针对SQL注入的动态标识符

这必然要求SQL语句中的标识符是动态用户输入。尽管预处理语句对于任何比较值的SQL语句与用户输入的分离都是完美的,但它们并不意味着用于表名或列名等标识符。 (也就是说,I 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

是的,但只要完整的字符串被认为是标识符,像'CHAR(96)'这样的函数不会被MySQL解释。 (编辑:我回答的评论已被删除) – David

+0

大声思考:我会让用户在表单中输入表格和列名。现在,这些可以验证为无意义的字符和代码。然后可以很容易地检查它们与'mysql数据字典'的匹配。任何不匹配,然后错误。我还会有一个表格和/或列的“白名单”。从提供的信息中生成所需的SQL是一项相当简单的任务。即。想'查询建设者'? –

+0

@RyanVincent谢谢,我会处理这些问题。一个最佳的解决方案将是像'TableCopier :: copyTables($ src,$ dest)'这样的方法。我肯定可以给这个方法写一个评论:«不要让它过分的价值!»。但是这并不能保护它不被使用,并在野外造成SQL漏洞。 – David

回答

-1

至于你提到的报价()为PDO功能,可用于转义列名以及数据。或者使用预先准备的语句,例如CREATE TABLE?喜欢 ?然后只执行查询。

+0

PDO预处理语句不可行[因为](https://secure.php.net/manual/en/pdo.prepare.php):»参数标记只能表示一个完整的数据文字«(但不是标识符)。 'quote()'方法需要从字符串中去掉第一个和最后一个''',这表明我不是用它的方式来使用它。此外,我在我的问题中链接的评论指出,转义标识符和转义字符串«有所不同。 – David

0

你总是想逃避`标识符,甚至表名和字段名称,因为也许明天他们将被保留字和打破你的查询。只要你正在使用准备好的语句(PDO,mysqli,或其他),你会没事的。请注意,PDO不允许转义表或字段名称。

你只需要细化你的过滤机制,至于什么表名等是允许的,而不是。你可以这样做:“CREATE TABLE {$ quoted_table_name} LIKE {$ table_name}”; ..用户使用占位符(?,或:name等)准备语句

编辑: 既然你需要保护的标识符,我看到2种方式:

  1. 围绕他们(')
  2. 过滤&转义传入值(mysql_real_escape_string或更好)。过滤将包括删除任何不必要的字符(您可能希望只允许使用字母[a-z] +或带数字的字母。
+0

PDO准备好的语句不可行[因为](https://secure.php.net/manual/en/pdo.prepare.php):»参数标记只能表示一个完整的数据文字«(但不是标识符)。 – David

+0

然后在普通的mysql中逃脱,PDO负责参数和查询分离。但回到你的问题,明白你正在执行的查询是什么?你不只是把表名称作为输入并执行查询?我不明白问题在哪里? –

+0

该查询实际上并不相关。问题是,如何在SQL查询中安全地使用_identifiers_(表名,列名)的用户输入。 – David