flawopen.com/SQL Injection in Java/MyBatis
MyBatis ${} vs. #{}: SQL Injection verhindern
Stell dir #{value} als geschütztes Wertefeld eines Prepared Statements vor: Die Datenbank erhält Daten. ${value} kopiert Text vor der Vorbereitung in SQL.
Gebundene Werte und roher SQL-Text
<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
Warum MyBatis beide Schreibweisen bietet
#{} bindet Werte als JDBC-Parameter in einem PreparedStatement. Ein Parameter ersetzt keine SQL-Syntax wie Tabelle, Spalte oder Sortierrichtung. ${} setzt Text direkt ein und escaped ihn nicht. Bevorzuge statische Statements oder <choose>. Sonst wähle den vollständigen Bezeichner aus einer serverseitigen Allowlist; interpolieren nie beliebigen Request-Text.
Wenn dynamische Bezeichner nötig sind
Ein Parameter ersetzt keinen Bezeichner. Ordne Sortieroptionen festen SQL-Teilen im Servercode zu (oder nutze <choose>). Übergib keine Client-Spalte, Tabelle oder ASC/DESC direkt an ${}. Escaping macht beliebiges SQL nicht sicher.
MyBatis-Mapper prüfen
rg -n -F '${' --glob '*.xml' --glob '*.java' .Häufige Fragen
Ja. Es gelten dieselben Regeln. ${column} in @Select fügt rohen Text ein; binde Werte mit #{value} und erlaube Bezeichner per Allowlist.
Nein. Prüfe Treffer; SQL kann anderswo zusammengesetzt werden. Ergänze XML- und Annotation-Checks und teste, ob Sortieroptionen nur erwartete feste SQL-Teile nutzen.