flawopen.com/SQL Injection in PHP/Doctrine ORM
Doctrine ORM protège-t-il contre l’injection SQL ?
Oui pour le DQL avec des paramètres liés. Concaténer des données dans du DQL ou du SQL natif réintroduit le risque des requêtes brutes.
$em->createQuery( "SELECT u FROM User u " . "WHERE u.id = $userId" );
$qb->select('u')
->from('User', 'u')
->where('u.id = :id')
->setParameter('id', $userId);
Les valeurs liées ne protègent pas la structure de la requête
setParameter() lie une valeur DQL que Doctrine convertit en paramètre SQL, séparé du texte de la requête. La concaténer dans createQuery() contourne cette protection. Même règle pour le SQL natif : Connection::executeQuery() est sûr avec des marqueurs et un tableau de paramètres, pas si l’entrée est interpolée dans la chaîne SQL.
Un paramètre ne remplace pas un identifiant
Un marqueur représente une valeur, pas un identifiant DQL, une colonne SQL, une table, un opérateur ni un sens de tri. La documentation de sécurité de l’ORM avertit que l’entrée utilisateur dans les méthodes d’expression de QueryBuilder peut encore former du DQL injectable. Gardez ces expressions dans le code de confiance et choisissez les options de tri depuis une liste fermée.
$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);
- ✓Liez chaque valeur externe avec setParameter() ou les marqueurs DBAL ; ne la concaténez jamais au DQL ou au SQL.
- ✓Traitez les méthodes d’expression QueryBuilder et les fragments DQL comme du code. Autorisez uniquement champs, tris, opérateurs et fonctions approuvés.
- ✓Pour le SQL natif, utilisez executeQuery($sql, $params) ou executeStatement($sql, $params) avec des marqueurs.
- ✓Examinez le flux des données et la structure de la requête. Une valeur liée peut toujours exposer des lignes non autorisées ; contrôlez l’autorisation séparément.
Auditer votre base de code
rg -n -g '*.php' 'createQuery\(|orderBy\(|addOrderBy\(|executeQuery\(' .Sources et références
- Doctrine ORM — paramètres QueryBuilder
- Doctrine ORM — sécurité
- Doctrine DBAL — requêtes préparées et paramètres
- FlawOpen — injection SQL en PHP