FlawOpen

flawopen.com/SQL Injection di Java/MyBatis

MyBatis ${} vs #{}: mencegah SQL Injection

Halaman referensi
Jawaban singkat

Bayangkan #{value} sebagai slot terlindungi pada prepared statement: database memperlakukannya sebagai data. ${value} menyalin teks ke SQL sebelum disiapkan.

Nilai terikat vs teks SQL mentah

TIDAK AMAN — teks mentah ${}
<select id="getUser">
  SELECT * FROM users
  WHERE id = ${id}
</select>
// Raw substitution: the SQL text changes
NILAI TERIKAT — #{}
<select id="getUser">
  SELECT * FROM users
  WHERE id = #{id}
</select>
// MyBatis creates a PreparedStatement parameter

Mengapa MyBatis menyediakan kedua sintaks

#{} mengikat nilai sebagai parameter JDBC PreparedStatement. Parameter tidak mewakili sintaks SQL seperti nama tabel, kolom, atau arah urutan. ${} mengganti teks langsung tanpa escape. Utamakan statement statis atau cabang <choose>. Jika perlu, pilih identifier utuh dari allowlist server; jangan interpolasikan teks permintaan sembarang.

Saat identifier dinamis diperlukan

Allowlist identifier atau fragmen SQL secara utuh

Parameter terikat tidak menggantikan identifier. Petakan pilihan urutan ke fragmen SQL tetap di server (atau gunakan <choose>). Jangan kirim kolom, tabel, atau ASC/DESC dari klien langsung ke ${}. Escape atau kutip tidak mengamankan SQL sembarang.

Cara mengaudit mapper MyBatis

rg -n -F '${' --glob '*.xml' --glob '*.java' .
Tinjau setiap hasil XML dan anotasi serta lacak asal nilai. Gunakan #{} untuk nilai; ${} harus berasal dari allowlist server terbatas. Pencarian menemukan sintaks, bukan semua SQL tak langsung.

Pertanyaan umum

Apakah ini berlaku untuk mapper berbasis anotasi?

Ya. Aturannya sama. ${column} di @Select menyisipkan teks mentah; ikat nilai dengan #{value} dan allowlist identifier.

Apakah mencari ${} cukup membuktikan kode aman?

Tidak. Tinjau hasil; SQL mungkin dirakit di tempat lain. Tambahkan pemeriksaan XML dan anotasi serta uji agar pilihan urutan hanya memakai fragmen tetap yang diharapkan.

Referensi

Lihat juga SQL Injection (CWE-89): cara kerja dan cara mencegahnya di setiap bahasa — flawopen.com MySQLi vs PDO: prepared statement yang aman Apakah NHibernate aman dari SQL Injection? Injeksi NoSQL MongoDB: filter kueri aman Apakah format string berbahaya untuk ID numerik? Apa itu kueri terparameterisasi? Apakah Prisma $queryRaw aman dari SQL Injection?