flawopen.com/SQL Injection en Java/MyBatis
MyBatis ${} et #{} : prévenir la SQL Injection
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
<select id="getUser">
SELECT * FROM users
WHERE id = ${id}
</select>
// Raw substitution: the SQL text changes
<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
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' .Questions fréquentes
Oui. Même règle : ${column} dans @Select insère du texte brut. Liez les valeurs avec #{value} et autorisez les identifiants par liste.
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.