flawopen.com/SQL Injection en Java/MyBatis
MyBatis ${} vs #{}: evitar SQL Injection
Piensa en #{value} como un campo protegido de una instrucción preparada: la base de datos recibe datos. ${value} copia texto al SQL antes de prepararlo.
Valores vinculados y texto SQL sin procesar
<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
Por qué MyBatis ofrece ambas sintaxis
#{} vincula valores con un parámetro JDBC PreparedStatement. Un parámetro no representa sintaxis SQL como tabla, columna u ordenación. ${} sustituye texto directamente y no lo escapa. Prefiere sentencias estáticas o ramas <choose>. Si hace falta, elige el identificador o fragmento desde una lista permitida del servidor; no interpoles texto arbitrario de la solicitud.
Cuándo se necesitan identificadores dinámicos
Un parámetro no sustituye identificadores. Para ordenar, asigna opciones a fragmentos SQL fijos del servidor (o usa <choose>). No pases columna, tabla ni ASC/DESC del cliente directamente a ${}. Escapar no vuelve seguro un fragmento arbitrario.
Cómo auditar mappers MyBatis
rg -n -F '${' --glob '*.xml' --glob '*.java' .Preguntas frecuentes
Sí. Se aplican las mismas reglas. ${column} en @Select inserta texto sin procesar; vincula valores con #{value} y limita identificadores con una lista.
No. Revisa los resultados; la búsqueda puede omitir SQL ensamblado en otro sitio. Añade comprobaciones para XML y anotaciones y prueba que las opciones de ordenación usen fragmentos fijos esperados.