【问题标题】:Why does PDO manual say that SQL injection is still possible with PDO?为什么 PDO 手册说 PDO 仍然可以进行 SQL 注入?
【发布时间】:2012-05-17 12:16:14
【问题描述】:

http://php.net/manual/en/pdo.prepared-statements.php

如果应用程序专门使用预准备语句,开发人员可以确保不会发生 SQL 注入(但是,如果查询的其他部分是使用非转义输入构建的,则仍然可能发生 SQL 注入)。

某些输入未转义的可能情况是什么?如果所有其他输入都使用 PDO 进入数据库,这是否可能?

我正在考虑使用 mysql_* 函数处理其他输入而不使用 mysql_real_escape_string 转义的场景。还有其他可能构成威胁的东西吗?

非常感谢。问候

【问题讨论】:

标签: php mysql


【解决方案1】:

这意味着您不能直接使用不受信任的值,例如作为列名或表名 - 或作为 LIMIT 参数。

例如,这是安全的:

$query = "SELECT * FROM tbl WHERE col = ?";

虽然这些不是:

$query = 'SELECT * FROM tbl WHERE col = ? LIMIT ' . $_GET['limit'];
$query = 'SELECT * FROM tbl WHERE ' . $_GET['field'] . ' = ?';
$query = "SELECT * FROM tbl WHERE col = ? AND othercol = '" . $_GET['other'] . "'";
$query = 'SELECT * FROM ' . $_GET['table'] . ' WHERE col = ?';

基本上,准备好的语句的占位符用于在经典查询中在单引号内使用转义值的地方。

如果您想知道为什么数据库通常不支持表名之类的占位符:除了动态表/列名并不常见的事实之外,数据库引擎通常会在准备好语句时对其进行优化。但是,如果不确切知道访问了哪些表/列,则无法正确完成此操作。

【讨论】:

  • 这不仅仅是标识符;对于不作为参数传递的值显然也是如此(正如@DaveRandom 的回答所暗示的那样)。
  • +1 这比我的好。 IIRC,你不能使用准备好的语句来安全地逃避你的第二个不安全的情况,因为它只适用于值而不是对象名。如果您确实必须允许用户在字段/表/数据库/等名称中输入,则需要将它们反引号并手动执行strpos() 类型的操作以检测恶意输入。我认为。虽然我可能是错的。
  • 认为这很明显 - 我已经为它添加了一个示例。 @DaveRandom:是的,但是如果您需要动态列名,您最好还是使用白名单。
  • 大家好,感谢您的回复。所以我想这样做的安全方法是将".$_GET['other'] ." 替换为? 并将$_GET['other'] 作为参数传递?谢谢
【解决方案2】:

考虑一下:

$sql = "SELECT * FROM ".$_GET['tablename']." WHERE somecol = ?";

因为我使用未转义的用户输入填充了表名,所以可以传入例如 public_table p LEFT JOIN hidden_table h ON h.id = p.id 并得到你不希望我得到的结果,即使你已经转义了传递给 @ 的值987654323@比较。

关键是,虽然准备好的语句可以安全地转义您在查询中传递给 ? 的任何用户输入,但它们无法转义在您将字符串传递给 prepare() 之前已经存在于字符串中的数据。

【讨论】:

    【解决方案3】:

    这意味着不要被诱使认为 PDO 是灵丹妙药......如果你使用准备好的语句,你仍然会受到攻击。

    【讨论】:

      猜你喜欢
      • 2016-11-08
      • 1970-01-01
      • 2014-10-14
      • 1970-01-01
      • 2019-02-13
      • 2015-08-20
      • 2018-01-19
      • 2013-02-27
      • 2014-12-05
      相关资源
      最近更新 更多