FlawOpen

flawopen.com/SQL Injection in PHP/Doctrine ORM

O Doctrine ORM é seguro contra injeção SQL?

Reference page
Resposta curta

Sim para DQL com parâmetros vinculados. Montar DQL ou SQL nativo por concatenação reabre o mesmo risco de qualquer consulta bruta.

INSEGURO — entrada vira sintaxe DQL
$em->createQuery(
  "SELECT u FROM User u "
  . "WHERE u.id = $userId"
);
SEGURO — escolha apenas expressões confiáveis
$qb->select('u')
  ->from('User', 'u')
  ->where('u.id = :id')
  ->setParameter('id', $userId);

Valores vinculados não protegem a estrutura da consulta

setParameter() vincula valores DQL, que o Doctrine converte em parâmetros SQL separados do texto da consulta. Concatenar entrada em createQuery() ignora essa proteção. O mesmo vale para SQL nativo: Connection::executeQuery() é seguro com placeholders e uma lista de parâmetros, mas não quando a entrada é interpolada na string SQL.

Parâmetros não substituem identificadores

Um placeholder representa um valor, não um identificador DQL, coluna SQL, nome de tabela, operador ou direção de ordenação. A documentação de segurança do ORM alerta que entrada do usuário em métodos de expressão do QueryBuilder ainda pode formar DQL injetável. Mantenha essas expressões no código confiável e mapeie campos e direções escolhidos pelo usuário por uma lista de permissões estrita.

INSEGURO — entrada vira sintaxe DQL
$qb->orderBy(
  'u.' . $request->query->get('sort'),
  $request->query->get('direction')
);
SEGURO — escolha apenas expressões confiáveis
$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);

Como revisar sua base de código

rg -n -g '*.php' 'createQuery\(|orderBy\(|addOrderBy\(|executeQuery\(' .
Revise cada ocorrência por concatenação ou interpolação, entrada do usuário em APIs de expressão e identificadores não limitados a uma lista fixa. Os resultados são candidatos à revisão, não prova de explorabilidade.

Fontes e referências

Veja também SQL Injection (CWE-89): como funciona e como evitar em todas as linguagens — flawopen.com EF Core FromSqlRaw: SQL parametrizado seguro FastAPI e SQL Injection: o que o Pydantic protege GORM Raw SQL: evite injeção SQL em Go É suficiente escapar aspas contra SQL Injection? Usar um ORM basta para prevenir SQL Injection? Knex.js é seguro contra SQL Injection?