FlawOpen

flawopen.com/SQL Injection in Java/MyBatis

MyBatis ${} vs. #{}: SQL Injection verhindern

Referenzseite
Kurzantwort

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

UNSICHER — Rohtext ${}
<select id="getUser">
  SELECT * FROM users
  WHERE id = ${id}
</select>
// Raw substitution: the SQL text changes
GEBUNDENER WERT — #{}
<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

Vollständigen SQL-Bezeichner oder -Teil erlauben

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' .
Prüfe XML und Annotationen und verfolge die Wertquelle. Nutze #{} für Werte; bei ${} muss der Bezeichner aus einer endlichen serverseitigen Allowlist stammen. Textsuche findet Syntax, nicht jede indirekte SQL-Erzeugung.

Häufige Fragen

Gilt das auch für Annotation-Mapper?

Ja. Es gelten dieselben Regeln. ${column} in @Select fügt rohen Text ein; binde Werte mit #{value} und erlaube Bezeichner per Allowlist.

Beweist eine Suche nach ${} die Sicherheit?

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.

Quellen

Siehe auch SQL-Injection (CWE-89): Funktionsweise und Schutz in jeder Sprache — flawopen.com MySQLi vs. PDO: sichere Prepared Statements Schützt NHibernate vor SQL-Injection? MongoDB NoSQL Injection: sichere Abfragefilter Können auch numerische IDs SQL Injection verursachen? Was ist eine parametrisierte Abfrage? Ist Prisma $queryRaw vor SQL-Injection sicher?