Doctrine queryBuilder:SQL addOrderBy() 方法中的注入风险?
Doctrine queryBuilder: SQL Injection risk in addOrderBy() method?
我在 Symfony
2.8 项目中使用 Doctrine
,我想知道在使用 addOrderBy()
方法时是否存在任何 SQL 注入的风险15=]:
// 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
而不是 ASC
或 DESC
。
我已经试过了,但是查询生成器似乎不接受由 ;
分隔的多个查询,这并不意味着不能进行任何 other/better 注入:-)
当然,通过过滤收到的结果并跳过所有无效的搜索选项,可以轻松解决问题。但我试图理解,如果 addOrderBy()
方法一般。 将任何值传递给该方法是否省事,Doctrine
将处理其余部分,还是存在潜在风险?
我想知道为什么 ->setParameter()
方法不起作用,就像使用 ->where()
时那样。
您可以使用 Expr
class: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/query-builder.html#the-expr-class
或者一个简单的function/method到return一个有效值:
function orderOption($option, $defaultOption = 'ASC') {
if (in_array(strtoupper($option), ['ASC', 'DESC']) {
return $option;
}
return $defaultOption;
}
简而言之,表单提交的列名实际上可以用于 sql 注入攻击。 Doctrine 假定您已正确验证列(和 table)名称。
条令代码相当容易阅读,对于这类问题值得一看:
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 有点复杂,但基本上第二个参数最终被传递,没有转义或过滤等。
I wonder why the ->setParameter() method does not work, as it would
when using ->where()
重要的概念是准备好的语句仅保护 值 而不是列或 table 名称。
因此,过滤来自野外的 table/column 个名称完全取决于您。查看源代码可以提供信息。
我在 Symfony
2.8 项目中使用 Doctrine
,我想知道在使用 addOrderBy()
方法时是否存在任何 SQL 注入的风险15=]:
// 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
而不是 ASC
或 DESC
。
我已经试过了,但是查询生成器似乎不接受由 ;
分隔的多个查询,这并不意味着不能进行任何 other/better 注入:-)
当然,通过过滤收到的结果并跳过所有无效的搜索选项,可以轻松解决问题。但我试图理解,如果 addOrderBy()
方法一般。 将任何值传递给该方法是否省事,Doctrine
将处理其余部分,还是存在潜在风险?
我想知道为什么 ->setParameter()
方法不起作用,就像使用 ->where()
时那样。
您可以使用 Expr
class: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/query-builder.html#the-expr-class
或者一个简单的function/method到return一个有效值:
function orderOption($option, $defaultOption = 'ASC') {
if (in_array(strtoupper($option), ['ASC', 'DESC']) {
return $option;
}
return $defaultOption;
}
简而言之,表单提交的列名实际上可以用于 sql 注入攻击。 Doctrine 假定您已正确验证列(和 table)名称。
条令代码相当容易阅读,对于这类问题值得一看:
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 有点复杂,但基本上第二个参数最终被传递,没有转义或过滤等。
I wonder why the ->setParameter() method does not work, as it would when using ->where()
重要的概念是准备好的语句仅保护 值 而不是列或 table 名称。
因此,过滤来自野外的 table/column 个名称完全取决于您。查看源代码可以提供信息。