【问题标题】:Doctrine queryBuilder: SQL Injection risk in addOrderBy() method?Doctrine queryBuilder:addOrderBy() 方法中的 SQL 注入风险?
【发布时间】:2017-04-22 12:08:39
【问题描述】:

我在Symfony 2.8 项目中使用Doctrine,我想知道在使用queryBuilderaddOrderBy() 方法时是否存在SQL 注入风险:

// Order options. Real code does not specify this manually, but receives 
// the options via user form input
$orderBy' = array(
    'column1' => 'ASC',
    'column2' => 'DESC',
    ...
    'columnN' => 'ASC',
);

$qb = $this->em->createQueryBuilder();
...

foreach ($orderBy as $column => $orderOption) {
     $qb->addOrderBy("e.$column", $orderOption);

     // Does not work:
     // $qb->addOrderBy("e.$column", ':orderOption')
     //  ->setParameter('orderOption', $orderOption);
     // 
     // Error: Expected end of string, got ':orderOption'"
}

// Result is something like:
...ORDER BY e0_.column1 ASC, e0_.column2 DESC...

问题在于,订单选项是通过用户表单输入接收的,可以将其操作为 ; DROP TABLE someTable 而不是 ASCDESC

我已经尝试过了,但是查询生成器似乎不接受由; 分隔的多个查询,这并不意味着不可能有任何其他/更好的注入 :-)

当然,通过过滤收到的结果并跳过所有无效的搜索选项,可以轻松解决问题。但我想了解,如果一般是addOrderBy() 方法。 将任何值传递给方法是否省钱,Doctrine 会处理其余部分,还是存在潜在风险?

我想知道为什么 ->setParameter() 方法不起作用,就像使用 ->where() 时一样。

【问题讨论】:

    标签: php symfony doctrine-orm sql-injection


    【解决方案1】:

    您可以使用Expr 类:http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/query-builder.html#the-expr-class

    或返回有效值的简单函数/方法:

    function orderOption($option, $defaultOption = 'ASC') {
        if (in_array(strtoupper($option), ['ASC', 'DESC']) {
            return $option;
        }
        return $defaultOption;
    }
    

    【讨论】:

    • 谢谢,但正如问题中所解释的那样,这与寻找保存过滤器功能无关,而是关于 addOrderBy() 是否首先存在风险。
    • 所以,使用Expr
    • 我不想使用Expr :) 我想了解使用addOrderBy() 是否存在风险..
    • 没有风险,因为查询构建器将创建 DQL 查询。可能发生的情况是引发异常。
    • 仅 DQL 并不能防止 SQL 注入。一些查询生成器可以被认为是保存的,但不是全部。问题是,addOrderBy() 是否保存。
    【解决方案2】:

    简短的回答是表单提交的列名实际上可以用于 sql 注入攻击。 Doctrine 假定您已正确验证列(和表)名称。

    教义代码相当容易阅读,对于这些类型的问题值得一看:

    public function addOrderBy($sort, $order = null)
    {
        $orderBy = ($sort instanceof Expr\OrderBy) ? $sort : new Expr\OrderBy($sort, $order);
    
        return $this->add('orderBy', $orderBy, true);
    }
    

    请注意,在查询中使用 Expr 没有任何价值。 Doctrine 会为您生成它们。

    $this->add 有点复杂,但基本上第二个参数最终被传递,没有转义或过滤等。

    我想知道为什么 ->setParameter() 方法不起作用,因为它会 当使用 ->where()

    重要的概念是准备好的语句只保护而不是列名或表名。

    同样,过滤来自野外的表/列名称完全由您决定。并且查看来源可以提供信息。

    【讨论】:

      猜你喜欢
      • 2012-07-17
      • 1970-01-01
      • 1970-01-01
      • 2019-07-13
      • 1970-01-01
      • 2022-10-22
      • 2018-04-27
      • 1970-01-01
      • 2018-11-06
      相关资源
      最近更新 更多