FlawOpen

flawopen.com/SQL Injection en Java/MyBatis

MyBatis ${} et #{} : prévenir la SQL Injection

Page de référence
Réponse courte

Imaginez #{value} comme une case protégée d’une requête préparée : la base reçoit une donnée. ${value} copie du texte dans SQL avant préparation.

Valeurs liées et texte SQL brut

DANGEREUX — texte brut ${}
<select id="getUser">
  SELECT * FROM users
  WHERE id = ${id}
</select>
// Raw substitution: the SQL text changes
VALEUR LIÉE — #{}
<select id="getUser">
  SELECT * FROM users
  WHERE id = #{id}
</select>
// MyBatis creates a PreparedStatement parameter

Pourquoi MyBatis propose les deux syntaxes

#{} lie une valeur via un paramètre JDBC PreparedStatement. Un paramètre ne représente pas une syntaxe SQL telle qu’une table, une colonne ou le sens du tri. ${} insère directement le texte, sans l’échapper. Préférez les instructions statiques ou <choose>. Sinon, choisissez l’identifiant ou fragment complet dans une liste serveur ; n’interpolez jamais un texte de requête arbitraire.

Quand des identifiants dynamiques sont nécessaires

Autoriser l’identifiant ou fragment SQL complet

Un paramètre ne remplace pas un identifiant. Pour le tri, associez les choix à des fragments fixes côté serveur (ou utilisez <choose>). Ne transmettez pas à ${} une colonne, table ou valeur ASC/DESC du client. L’échappement ne sécurise pas un fragment arbitraire.

Auditer les mappers MyBatis

rg -n -F '${' --glob '*.xml' --glob '*.java' .
Examinez les résultats XML et annotations, puis retracez la valeur. Utilisez #{} pour les valeurs ; pour ${}, exigez une liste finie côté serveur. La recherche repère la syntaxe, pas toute construction indirecte.

Questions fréquentes

Cela concerne-t-il les mappers avec annotations ?

Oui. Même règle : ${column} dans @Select insère du texte brut. Liez les valeurs avec #{value} et autorisez les identifiants par liste.

Une recherche de ${} prouve-t-elle la sécurité ?

Non. Examinez les résultats ; SQL peut être assemblé ailleurs. Ajoutez des contrôles XML/annotations et testez que les choix de tri utilisent uniquement des fragments fixes attendus.

Références

À voir aussi Injection SQL (CWE-89) : fonctionnement et prévention dans chaque langage — flawopen.com MySQLi vs PDO : prepared statements sûres NHibernate protège-t-il contre les injections SQL ? Injection NoSQL MongoDB : filtres sûrs Un ID numérique peut-il aussi provoquer une injection SQL ? Qu'est-ce qu'une requête paramétrée ? Prisma $queryRaw protège-t-il contre les injections SQL ?