Доктрина 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().

Author: Andrei Herford, 2016-12-07

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() не работает, как это было бы при использовании ->где()

Важная концепция заключается в том, что подготовленные инструкции защищают только значения , а не имена столбцов или таблиц.

Итак, опять же, вам полностью решать, как фильтровать имена таблиц/столбцов, исходящие из дикой природы. И взгляд на источник может быть информативным.

 7
Author: Cerad, 2016-12-07 14:31:02

Вы можете использовать класс 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;
}
 1
Author: rogeriolino, 2016-12-07 14:04:44