FlawOpen

flawopen.com/SQL Injection in PHP/Doctrine ORM

Защищает ли Doctrine ORM от SQL-инъекций?

Reference page
Короткий ответ

Да, если значения в DQL передаются параметрами. Конкатенация DQL или SQL возвращает риск обычного сырого запроса.

НЕБЕЗОПАСНО — ввод становится синтаксисом DQL
$em->createQuery(
  "SELECT u FROM User u "
  . "WHERE u.id = $userId"
);
БЕЗОПАСНО — только доверенные выражения
$qb->select('u')
  ->from('User', 'u')
  ->where('u.id = :id')
  ->setParameter('id', $userId);

Связанные значения не защищают структуру запроса

setParameter() связывает значение DQL, которое Doctrine преобразует в отдельный SQL-параметр. Конкатенация в createQuery() обходит эту защиту. То же для SQL: Connection::executeQuery() безопасен с плейсхолдерами и массивом параметров, но не при вставке ввода в строку SQL.

Параметром нельзя заменить идентификатор

Плейсхолдер задаёт значение, а не идентификатор DQL, столбец SQL, таблицу, оператор или направление сортировки. Руководство ORM предупреждает: пользовательский ввод в методах выражений QueryBuilder всё ещё может сформировать DQL-инъекцию. Оставляйте выражения в доверенном коде и выбирайте поля и порядок только из строгого списка разрешённых значений.

НЕБЕЗОПАСНО — ввод становится синтаксисом DQL
$qb->orderBy(
  'u.' . $request->query->get('sort'),
  $request->query->get('direction')
);
БЕЗОПАСНО — только доверенные выражения
$fields = [
    'name' => 'u.name',
    'created' => 'u.createdAt',
];
$directions = ['asc' => 'ASC', 'desc' => 'DESC'];

$key = (string) $request->query->get('sort', 'name');
$sort = $fields[$key] ?? $fields['name'];
$requestedDirection = strtolower(
    (string) $request->query->get('direction', 'asc')
);
$direction = $directions[$requestedDirection] ?? 'ASC';

$qb->orderBy($sort, $direction);

Проверка кодовой базы

rg -n -g '*.php' 'createQuery\(|orderBy\(|addOrderBy\(|executeQuery\(' .
Проверьте совпадения на конкатенацию, ввод в API выражений и идентификаторы вне фиксированного списка. Результаты указывают на места проверки, но не доказывают эксплуатируемость.

Источники и ссылки

См. также SQL-инъекции (CWE-89): как они работают и как их предотвратить в любом языке — flawopen.com EF Core FromSqlRaw: безопасный SQL с параметрами FastAPI и SQL Injection: границы защиты Pydantic GORM Raw SQL: защита от SQL-инъекций в Go Достаточно ли экранировать кавычки от SQL Injection? Достаточно ли ORM, чтобы предотвратить SQL-инъекции? Защищает ли Knex.js от SQL-инъекций?