Доктрина QueryBuilder: Риск внедрения SQL в метод addOrderBy()?
Я использую Doctrine
в проекте Symfony
2.8, и мне интересно, существует ли какой-либо риск SQL-инъекций при использовании метода addOrderBy()
queryBuilder
:
// 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
.
Я уже пробовал это, но конструктор запросов, похоже, не принимает несколько запросов, разделенных ;
, что не означает, что не может быть другого/лучшего инъекции:-)
Конечно, проблему можно легко решить, отфильтровав полученные результаты и пропустив все недопустимые параметры поиска. Но я пытаюсь понять, работает ли метод addOrderBy()
в целом. Можно ли сохранить какое-либо значение для метода и Doctrine
обработает остальное, или существует потенциальный риск?
Интересно, почему метод ->setParameter()
не работает, как это было бы при использовании ->where()
.
2 answers
Короткий ответ заключается в том, что имена столбцов, представленные формой, на самом деле могут быть использованы для атаки с использованием sql-инъекции. Доктрина предполагает, что у вас есть правильно проверенные имена столбцов (и таблиц).
Код доктрины довольно легко читается, и на него стоит обратить внимание для таких вопросов:
public function addOrderBy($sort, $order = null)
{
$orderBy = ($sort instanceof Expr\OrderBy) ? $sort : new Expr\OrderBy($sort, $order);
return $this->add('orderBy', $orderBy, true);
}
Обратите внимание, что использование Expr в ваших запросах вообще не имеет смысла. Доктрина заботится о том, чтобы создать их для вас.
$это->добавить немного сложнее, но в основном второй аргумент в конечном итоге передается без экранирования или фильтрации и т.д.
Интересно, почему метод ->setParameter() не работает, как это было бы при использовании ->где()
Важная концепция заключается в том, что подготовленные инструкции защищают только значения , а не имена столбцов или таблиц.
Итак, опять же, вам полностью решать, как фильтровать имена таблиц/столбцов, исходящие из дикой природы. И взгляд на источник может быть информативным.
Вы можете использовать класс 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;
}