Doctrine expr - "literal"函数是否在内部使用预准备语句?



对于通常的情况,我们有与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(), '%_') . '%')));

简而言之,您提供的语句不安全。

QueryExpr中的方法不会自动将值转换为参数占位符。

>QueryExpr::literal

说明有效地使用QueryExpr::literal仅将值转换为 DQL 语句的文本字符串值,并根据需要将提供的值括在引号中。虽然该方法确实从提供的值中转义单引号,但这样做并不能防止所有 SQL 注入方法。[原文如此]

在您的第一种情况下

$expr = $em->getExpressionBuilder();
$orX = $expr->orX();
$orX->add(
$expr->lt(
'entityName.field - ' . $expr->literal($rule->getValue()), 
$expr->literal(self::MAX_ERROR)
)
);
//...
$qb = $em->createuQueryBuilder()
->where($orX);
dump($qb->getQuery()->getSQL());

如果$rule->getValue()是实数,则生成的SQL语句将成为"文字"数值。

WHERE (
(alias.column - 10 < 2)
OR
(...)
)

如果$rule->getValue()self::MAX_VALUE是数字字符串(可能会产生意外结果(,则生成的SQL输出将为:

WHERE (
(alias.column - '10' < '2')
OR
(...)
)

$qb->getQuery()->getParameters()将是一个空ArrayCollection,因为没有添加其他参数。


防止 SQL 注入

若要确保语句免受 SQL 注入的影响,必须在语句中声明参数占位符,并使用setParameter将参数值绑定到占位符。

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

如果有多个占位符,则需要根据需要跟踪和绑定它们。

$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);

处理嵌套条件

从您评论中的问题:

你如何处理可变数量的条件和混合的地方 与或在哪里没有 expr?类似于 WHERE 条件 1 和 (或条件 1 或条件 2 或...或或条件 N(

您可以使用所需的andXorX分组创建多个嵌套条件以提供给WHERE子句。

$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);

或者,您可以使用andWhereorWhere将表达式添加到主WHERE子句部分,但您需要使用表达式生成器来更改嵌套条件分组。

$qb
->orWhere($andXA, $andXB);

这将产生一个WHERE子句,例如

WHERE ((expr1 AND expr2) OR (expr3 AND expr4))
<小时 />

处理参数

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

但是,ORM 和 DBAL 以及DoctrineDBALConnection::executeQuery方法的 Doctrine 2.1+QueryBuilder确实支持参数化值数组和重复使用相同的命名参数,这与PDOMySQLi预准备语句不同。[原文如此]。在内部,Doctrine 会将参数值数组和重复的参数占位符值转换为单独的参数占位符,以发送到 PDO 准备语句。

$expr = $em->getExpressionBuilder();
$qb
->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);

生成的 SQL 输出。

WHERE w0_.a IN(?, ?, ?)
AND w0_.b < ?
AND w0_.c > ?

生成的查询生成器参数:

array(array("a", "b", "c"), 1, 1)

生成的PDO参数:

array("a", "b", "c", 1, 1)

防止通配符%注入

若要将 like 语句与参数占位符一起使用,必须在setParameter()值中指定通配符%_

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

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

使用反斜杠作为LIKE通配符或 SQL 查询的转义字符也被认为是不好的做法。由于它不是 ANSI SQL 标准,因此它与 PHP 转义字符相同,并且转义字符可能会根据服务器配置而更改。请参阅此问题转义 MySQL 通配符以获取更详细的答案。

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

从 2.7 - 4.0.x-dev(当前(开始,DBAL 表达式生成器支持转义字符作为第三个参数。[原文如此]

public function like($x, $y/*, ?string $escapeChar = null */)
{
return $this->comparison($x, 'LIKE', $y) .
(func_num_args() >= 3 ? sprintf(' ESCAPE %s', func_get_arg(2)) : '');
}
$value = 'test%';
$d_qb = $em->getConnection()->createQueryBuilder();
$d_expr = $d_qb->expr();
$d_qb
->where($d_expr->like('a', ':a', $expr->literal('#')))
->setParameter('a', '%' . preg_replace('/([#%_])/', '#$0', $value) . '%');

生成的 SQL 查询:

WHERE c0_.column LIKE ? ESCAPE '#'

结果参数:

array("%test#%%")

相关内容

  • 没有找到相关文章

最新更新