FlawOpen

flawopen.com/SQL Injection in PHP/Doctrine ORM

¿Doctrine ORM es seguro frente a la inyección SQL?

Reference page
Respuesta breve

Sí para DQL con parámetros vinculados. Construir DQL o SQL nativo concatenando texto vuelve a introducir el riesgo de cualquier consulta sin parametrizar.

INSEGURO — la entrada se convierte en sintaxis DQL
$em->createQuery(
  "SELECT u FROM User u "
  . "WHERE u.id = $userId"
);
SEGURO — usa expresiones de confianza
$qb->select('u')
  ->from('User', 'u')
  ->where('u.id = :id')
  ->setParameter('id', $userId);

Los valores vinculados no protegen la estructura de la consulta

setParameter() vincula valores DQL, que Doctrine traduce a parámetros SQL separados del texto de consulta. Concatenar datos en createQuery() elude esa protección. La misma regla se aplica a SQL nativo: Connection::executeQuery() es seguro con marcadores y una lista de parámetros, pero no si interpolas la entrada en la cadena SQL.

Los parámetros no sustituyen identificadores

Un marcador representa un valor, no un identificador DQL, columna SQL, tabla, operador ni dirección de ordenación. La guía de seguridad del ORM advierte que la entrada en métodos de expresión de QueryBuilder aún puede crear DQL inyectable. Mantén esas expresiones en código confiable y asigna las opciones de ordenación a una lista estricta de valores permitidos.

INSEGURO — la entrada se convierte en sintaxis DQL
$qb->orderBy(
  'u.' . $request->query->get('sort'),
  $request->query->get('direction')
);
SEGURO — usa expresiones de confianza
$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);

Cómo revisar tu código

rg -n -g '*.php' 'createQuery\(|orderBy\(|addOrderBy\(|executeQuery\(' .
Revisa cada coincidencia para detectar concatenación o interpolación, entrada en APIs de expresiones e identificadores que no provienen de una lista fija. Los resultados son candidatos a revisión, no una prueba de explotabilidad.

Fuentes y referencias

Véase también Inyección SQL (CWE-89): cómo funciona y cómo evitarla en cada lenguaje — flawopen.com EF Core FromSqlRaw: SQL parametrizado seguro FastAPI y SQL Injection: qué protege Pydantic GORM Raw SQL: evita la inyección SQL en Go ¿Basta escapar comillas para evitar SQL Injection? ¿Basta con usar un ORM para prevenir la inyección SQL? ¿Knex.js es seguro frente a SQL Injection?