flawopen.com/SQL Injection/ID numerik
Mengapa format string berbahaya bahkan untuk ID numerik?
Risiko tidak ditentukan oleh arti nilai di dunia nyata, melainkan karena kueri dibuat dengan menyambungkan teks. “Ini selalu angka” adalah asumsi tentang data, bukan jaminan yang ditegakkan kode.
Saat asumsi gagal
Parameter kueri URL atau kolom formulir dikirim sebagai teks, apa pun tipe yang diharapkan kolom database. Tanpa validasi tipe eksplisit, framework tidak mencegah pengiriman id=1 OR 1=1 sebelum kode menerima nilainya.
Kode yang aman hari ini karena ID selalu berasal dari sumber internal tepercaya dapat menjadi rentan saat pemanggil baru meneruskan nilai pengguna ke fungsi yang sama. Kerentanan itu sudah laten dan menunggu perubahan tersebut.
Terutama dalam bahasa bertipe dinamis, nilai yang tampak numerik di log masih bisa berupa string dengan karakter tambahan. Tanpa validasi eksplisit, tipe yang diharapkan belum tentu sama dengan tipe sebenarnya.
Tetap parameterisasikan kueri setelah validasi tipe
Validasi ID sesuai format yang diharapkan aplikasi, lalu teruskan melalui API parameter driver database. Validasi melindungi kontrak input; parameterisasi mencegah input ditafsirkan sebagai sintaks SQL. Perilaku driver pada protokol dapat berbeda, jadi jangan menganggap semua driver mengirim nilai dengan cara yang sama. Parameter PostgreSQL tidak dapat mewakili identifier tabel atau kolom; pilih struktur kueri dinamis dari allowlist tetap di aplikasi.
Ikat nilai numerik dan validasi maknanya
Jika aplikasi memerlukan tipe tersebut, validasi ID sebagai bilangan bulat positif yang aman, tetapi tetap ikat sebagai nilai kueri. Validasi melindungi kontrak input aplikasi; parameterisasi menjaga input agar tidak menjadi sintaks SQL. Parameter PostgreSQL tidak dapat menggantikan identifier tabel atau kolom, jadi pilih struktur kueri dinamis dari allowlist tetap di aplikasi.
const rawId = new URL(request.url).searchParams.get("id");
const result = await pool.query(
`SELECT id FROM users WHERE id = ${rawId}`
);
const rawId = new URL(request.url).searchParams.get("id");
if (rawId === null || !/^[0-9]+$/.test(rawId)) {
return new Response("Invalid id", { status: 400 });
}
const id = Number(rawId);
if (!Number.isSafeInteger(id) || id < 1) {
return new Response("Invalid id", { status: 400 });
}
const result = await pool.query(
"SELECT id FROM users WHERE id = $1",
Array.of(id)
);
Referensi
- flawopen.com — SQL Injection (semua bahasa)
- Apa itu kueri terparameterisasi?
- node-postgres — Parameterized query API