Doctrine expr-“文字”功能是否在内部使用准备好的语句?

问题描述 投票:0回答:1

在通常情况下,具有与setParameters配对的andWhere / orWhere函数可以正确地防止注入。

我的案子比较复杂,我想确保一切都安全。如果我正确阅读了学说代码,似乎使用文字会产生相同的效果,但是我不确定是否可以...请问。确认/确认以下2种情况是安全的(都使用预备语句防止SQL注入和通配符注入)?

第一种情况

$expr = $queryBuilder->expr()->orX();
$expr->add($queryBuilder->expr()->lt('entityName.field - ' . $queryBuilder->expr()->literal($rule->getValue()), $queryBuilder->expr()->literal(self::MAX_ERROR))); // Since the second part is a constant (and a numeric one) it shouldn't need literal but... can't hurt.

第二种情况

$expr = $queryBuilder->expr()->orX();
$expr->add($queryBuilder->expr()->like('entityName.field', $queryBuilder->expr()->literal(addcslashes($rule->getValue(), '%_') . '%')));
php symfony doctrine-orm prepared-statement sql-injection
1个回答
0
投票

简而言之,您提供的任何陈述都不安全。

Query\Expr中的方法不会自动将您的值转换为参数占位符。


Query\Expr的说明

有效地使用Query\Expr:literal仅将值转换为DQL语句的文字字符串值,并将提供的值适当地括在引号中。尽管该方法的确从提供的值中转义了单引号,但这样做并不能防止所有SQL注入方法。 Query\Expr:literal

第一种情况

[sic]

如果$expr = $em->getExpressionBuilder(); $qb = $em->createuQueryBuilder(); $orX = $expr->orX(); $orX->add( $expr->lt( 'entityName.field - ' . $expr->literal($rule->getValue()), $expr->literal(self::MAX_ERROR) ) ); //... $qb->where($orX); dump($qb->getQuery()->getSQL()); 是实数,则生成的SQL语句将成为“文字”数字值。

$rule->getValue()

如果WHERE ( (alias.column - 10 < 2) OR (...) ) $rule->getValue()是数字字符串(可能会产生意外的结果),则生成的SQL输出将是:

self::MAX_VALUE

并且WHERE ( (alias.column - '10' < '2') OR (...) ) 将为空的$qb->getQuery()->getParameters(),因为未添加其他参数。


防止SQL注入

为了确保您的语句不受SQL注入的影响,您必须在语句中声明参数占位符,并使用ArrayCollectionsetParameter

bind the parameter values to the placeholders

如果您有多个占位符,则需要适当地跟踪和绑定它们。

$orX->add(
    $expr->lt(
        'entityName.field - :rule_value', 
        ':max'
    )
);
$qb->setParameter('rule_value', $rule->getValue());
$qb->setParameter('max', self::MAX_VALUE);

处理嵌套标准

来自您评论中的问题:

您如何处理和混合的可变数量的条件有or哪里没有expr?像WHERE condition1和(或条件1或条件2或...或条件N)

您可以通过使用所需的$v = 0; for (/*...*/) { $param = \sprintf('rule_value%d', $v++); $orX->add( $expr->lt( "entityName.field - :$param", ':max' ) ); $qb->setParameter($param, $rule->getValue()); } $qb->setParameter('max', self::MAX_VALUE); WHERE分组来创建多个嵌套标准,以提供给andX子句。

orX

$expr->orX(
   $expr->andX(
      'expr1',
      'expr2'
   ),
   $expr->andX(
      'expr3',
      'expr4'
   ),
);

或者,您可以使用$andXA = $expr>andX(); $andXB = $expr->andX(); $orX = $expr->orX(); $andXA->add('expr1'); $andXA->add('expr2'); $andXB->add('expr3'); $andXB->add('expr4'); $orX->add($andXA); $orX->add($andXB); WHERE将表达式添加到主要的andWhere子句部分,但是您需要使用表达式生成器来更改嵌套条件分组。

orWhere

将产生像$qb ->orWhere($andXA, $andXB); 子句的

WHERE

处理参数

为了消除与参数的混淆,DQL不支持值数组。 DQL只是查询Doctrine应用程序已知的对象符号的一种标准化方法。

但是,对于ORM和DBAL而言,Doctrine 2.1+ WHERE ((expr1 AND expr2) OR (expr3 AND expr4)) 以及QueryBuilder方法的确支持对值数组进行参数化并重复使用相同的命名参数,与Doctrine\Connection::executeQueryPDO准备好的语句不同。 MySQLi。在内部,Doctrine会将参数值和重复的参数占位符值的数组转换为单个参数占位符,以发送到PDO准备好的语句。

[sic]

结果SQL输出。

$expr = $em->getExpressionBuilder()
$qb = $em->createQueryBuilder()
   ->select(['cn'])
   ->from(\App\Entity\Entity::class, 'cn')
   ->where($expr->andX(
        $expr->in('cn.a', ':a'),
        $expr->lt('cn.b', ':b'),
        $expr->gt('cn.c', ':b')
    ))
   ->setParameter('a', ['a', 'b', 'c'])
   ->setParameter('b', 1);

结果参数:

SELECT w0_.id, w0_.a, w0_.b, w0_.c
FROM table_name AS w0_
WHERE w0_.a IN(?)
AND w0_.b < ?
AND w0_.c > ?

防止通配符array(array("a","b","c"),1,1) 注入

要使用like语句,必须在%值内指定通配符%_

setParameter()

缺点是,如果变量还包含通配符,则可能会产生不希望的结果。为防止通配符注入,您可以指定如何在查询中对通配符进行转义,这将与查询构建器和参数占位符一起使用。

$qb->setParameter('0', '%' . $value . '%');

DBAL QueryBuilder支持将转义字符作为提供的参数。

$qb
    ->where($expr->like('a', ':a ESCAPE ' . $expr->literal('#')))
    ->setParameter('a', '%'. preg_replace('/([%_])/', '#$0', $value) . '%');

结果SQL查询:

$d_qb = $em->getConnection()->createQueryBuilder();
$d_expr = $d_qb->expr();
$d_qb
    ->where($d_expr->like('a', ':a', '#'))
    ->setParameter('a', '%'. preg_replace('/([%_])/', '#$0', $value) . '%');

结果参数:

WHERE c0_.column LIKE ? ESCAPE '#'
© www.soinside.com 2019 - 2024. All rights reserved.