【问题标题】:escaping column name with PDO使用 PDO 转义列名
【发布时间】:2012-11-07 01:10:05
【问题描述】:

我有一个类似的函数

function getInfoById($id, $info) {

}

这个想法是让查询成为"SELECT $info FROM table WHERE id = $id"

这不适用于 PDO,因为您无法转义列名。我也不想使用"SELECT *",因为这不是返回更大的结果集并使用更多内存吗?

【问题讨论】:

标签: php pdo


【解决方案1】:

我会用一些正则表达式过滤掉它。把事情简单化。

另外,你应该绑定$id 并让它成为:id

$info = preg_replace('/[^A-Za-z0-9_]+/', '', $info);

$stmt = $pdo->prepare('SELECT $info FROM table WHERE id = :id'); 
$stmt->bindParam(':id', $id);
$stmt->execute();

【讨论】:

  • 嗯,它比插入任意 $info 更好,但它是一个不完整的解决方案。例如,如果我的列名是order(SQL 保留字),则查询中断。
  • @BillKarwin bill,我同意,尽管我只是在说明一点。就像你上面说的,白名单是要走的路,这是我更喜欢自己处理这些事情的方式。我在这里说了同样的话:stackoverflow.com/questions/13424009/updating-sql-column/… 刚刚浏览了你的注射幻灯片,好东西。
  • 好吧,在它周围加上引号 SELECT "$info" FROM... 这也应该允许查询用作列
【解决方案2】:

是的,PDO 没有用于分隔标识符(如表名和列名)的内置函数。 PDO::quote() 函数仅适用于字符串文字和日期文字。

不管怎样,当我在 Zend Framework 上工作时,我实现了一个 quoteIdentifier() 函数。

SELECT * 获取所有列是对的,这可能会使用更多内存并破坏覆盖索引的好处。

我的建议是将列名列入白名单。也就是说,确保 $info 实际上命名为table 的列。然后您不必担心列名不存在,或包含奇怪的字符,或任何东西。您可以控制可合法放入查询的列集。

无论如何,您还应该对列名进行分隔。如果列名包含标点符号、空格、国际字符或与 SQL 保留字匹配,则必须使用分隔标识符。见Do different databases use different name quote?

function getInfoById($id, $info) {
    // you can make this a literal list, or query it from DESC or INFORMATION_SCHEMA
    $cols = array('col1', 'col2', 'col3');

    if (array_search($info, $cols) === false) {
      return false;
    }
    $sql = "SELECT `$info` FROM table WHERE id = :id";
    $stmt = $pdo->prepare($sql);
    if ($stmt === false) {
      return false;
    }
    . . .
}

我在演示文稿SQL Injection Myths and Fallacies 中展示了更多白名单示例。

【讨论】:

  • 我同意,白名单是必经之路。
  • in_arraytrue 进行严格比较
【解决方案3】:

如何使用引号和子字符串。

$sql = 'SELECT * FROM table WHERE `' . substr($db->quote($field), 1, -1) . '` = :id';

这将删除转义字段周围的引号。

【讨论】:

  • 危险!如果$field 包含反引号,这将严重失败并允许 SQL 注入。
猜你喜欢
  • 2010-12-05
  • 1970-01-01
  • 2014-03-18
  • 1970-01-01
  • 1970-01-01
  • 2021-06-05
  • 1970-01-01
  • 2012-11-12
  • 2012-11-04
相关资源
最近更新 更多