Saya tahu bahwa PreparedStatements menghindari / mencegah SQL Injection. Bagaimana cara melakukannya? Apakah kueri formulir akhir yang dibuat menggunakan PreparedStatements akan berupa string atau sebaliknya?
Saya tahu bahwa PreparedStatements menghindari / mencegah SQL Injection. Bagaimana cara melakukannya? Apakah kueri formulir akhir yang dibuat menggunakan PreparedStatements akan berupa string atau sebaliknya?
Jawaban:
Masalah dengan injeksi SQL adalah, input pengguna digunakan sebagai bagian dari pernyataan SQL. Dengan menggunakan pernyataan yang sudah disiapkan, Anda dapat memaksa input pengguna untuk ditangani sebagai konten parameter (dan bukan sebagai bagian dari perintah SQL).
Tetapi jika Anda tidak menggunakan input pengguna sebagai parameter untuk pernyataan yang Anda siapkan, melainkan membangun perintah SQL Anda dengan menggabungkan string, Anda masih rentan terhadap injeksi SQL bahkan saat menggunakan pernyataan yang sudah disiapkan.
Pertimbangkan dua cara untuk melakukan hal yang sama:
PreparedStatement stmt = conn.createStatement("INSERT INTO students VALUES('" + user + "')");
stmt.execute();
Atau
PreparedStatement stmt = conn.prepareStatement("INSERT INTO student VALUES(?)");
stmt.setString(1, user);
stmt.execute();
Jika "pengguna" berasal dari input pengguna dan input pengguna adalah
Robert'); DROP TABLE students; --
Kemudian dalam contoh pertama, Anda akan disemprot. Di detik, Anda akan aman dan Tabel Bobby Kecil akan didaftarkan ke sekolah Anda.
Untuk memahami bagaimana PreparedStatement mencegah SQL Injection, kita perlu memahami tahapan eksekusi SQL Query.
1. Tahap Penyusunan. 2. Tahap Eksekusi.
Setiap kali mesin server SQL menerima kueri, itu harus melewati fase di bawah ini,
Fase Parsing dan Normalisasi: Dalam fase ini, Query diperiksa untuk sintaks dan semantik. Ini memeriksa apakah tabel referensi dan kolom yang digunakan dalam kueri ada atau tidak. Ini juga memiliki banyak tugas lain yang harus dilakukan, tetapi jangan membahas secara detail.
Tahap Penyusunan: Dalam tahap ini, kata kunci yang digunakan dalam kueri seperti pilih, dari, di mana dll diubah ke dalam format yang dapat dimengerti oleh mesin. Ini adalah fase di mana kueri diinterpretasikan dan tindakan terkait yang akan diambil diputuskan. Ini juga memiliki banyak tugas lain yang harus dilakukan, tetapi jangan membahas secara detail.
Rencana Optimasi Kueri: Dalam fase ini, Pohon Keputusan dibuat untuk menemukan cara kueri dapat dieksekusi. Ia menemukan sejumlah cara di mana kueri dapat dieksekusi dan biaya yang terkait dengan setiap cara menjalankan Kueri. Itu memilih rencana terbaik untuk mengeksekusi kueri.
Cache: Paket terbaik yang dipilih dalam Paket pengoptimalan kueri disimpan dalam cache, sehingga setiap kali kueri yang sama masuk, tidak harus melalui Fase 1, Fase 2, dan Fase 3 lagi. Ketika kueri lain kali masuk, itu akan diperiksa langsung di Cache dan diambil dari sana untuk dieksekusi.
Tahap Eksekusi:
Dalam fase ini, kueri yang disediakan dijalankan dan data dikembalikan ke pengguna sebagai ResultSet
objek.
PreparedStatements bukanlah kueri SQL lengkap dan berisi placeholder, yang pada waktu proses diganti dengan data yang disediakan pengguna sebenarnya.
Setiap kali PreparedStatment yang berisi tempat penampung diteruskan ke mesin SQL Server, melewati fase di bawah ini
UPDATE set pengguna username =? dan kata sandi =? DI MANA id =?
Kueri di atas akan diurai, dikompilasi dengan placeholder sebagai perlakuan khusus, dioptimalkan, dan disimpan dalam cache. Kueri pada tahap ini sudah disusun dan diubah dalam format yang dapat dimengerti mesin. Jadi kita dapat mengatakan bahwa Query disimpan dalam cache adalah Pre-Compiled dan hanya placeholder yang perlu diganti dengan data yang disediakan pengguna.
Sekarang pada saat berjalan ketika data yang disediakan pengguna masuk, Kueri yang Dikompilasi Sebelumnya diambil dari Cache dan placeholder diganti dengan data yang disediakan pengguna.
(Ingat, setelah placeholder diganti dengan data pengguna, kueri akhir tidak dikompilasi / ditafsirkan lagi dan mesin SQL Server memperlakukan data pengguna sebagai data murni dan bukan SQL yang perlu diurai atau dikompilasi lagi; itulah keindahan PreparedStatement. )
Jika kueri tidak harus melalui fase kompilasi lagi, maka data apa pun yang diganti di tempat penampung diperlakukan sebagai data murni dan tidak memiliki arti bagi mesin SQL Server dan langsung menjalankan kueri.
Catatan: Ini adalah fase kompilasi setelah fase penguraian, yang memahami / menafsirkan struktur kueri dan memberikan perilaku yang berarti padanya. Dalam kasus PreparedStatement, kueri dikompilasi hanya sekali dan kueri terkompilasi yang di-cache diambil setiap saat untuk menggantikan data pengguna dan mengeksekusi.
Karena fitur kompilasi satu kali dari PreparedStatement, ini bebas dari serangan SQL Injection.
Anda bisa mendapatkan penjelasan rinci dengan contoh di sini: https://javabypatel.blogspot.com/2015/09/how-prepared-statement-in-java-prevents-sql-injection.html
SQL yang digunakan dalam PreparedStatement telah dikompilasi sebelumnya pada driver. Sejak saat itu, parameter dikirim ke driver sebagai nilai literal dan bukan bagian SQL yang dapat dieksekusi; jadi tidak ada SQL yang bisa diinjeksi menggunakan parameter. Efek samping lain yang menguntungkan dari PreparedStatements (precompilation + send only parameter) adalah peningkatan kinerja saat menjalankan pernyataan beberapa kali bahkan dengan nilai yang berbeda untuk parameter (dengan asumsi bahwa driver mendukung PreparedStatements) karena driver tidak harus melakukan parsing dan kompilasi SQL masing-masing waktu parameter berubah.
Saya kira itu akan menjadi string. Tetapi parameter input akan dikirim ke database & cast / konversi yang sesuai akan diterapkan sebelum membuat pernyataan SQL yang sebenarnya.
Sebagai contoh, mungkin mencoba dan melihat apakah CAST / Konversi berfungsi.
Jika berhasil, itu bisa membuat pernyataan akhir darinya.
SELECT * From MyTable WHERE param = CAST('10; DROP TABLE Other' AS varchar(30))
Coba contoh dengan pernyataan SQL yang menerima parameter numerik.
Sekarang, coba lewati variabel string (dengan konten numerik yang dapat diterima sebagai parameter numerik). Apakah itu menimbulkan kesalahan?
Sekarang, coba berikan variabel string (dengan konten yang tidak dapat diterima sebagai parameter numerik). Lihat apa yang terjadi?
Pernyataan yang disiapkan lebih aman. Ini akan mengubah parameter ke tipe yang ditentukan.
Misalnya stmt.setString(1, user);
akan mengubah user
parameter menjadi String.
Misalkan parameter berisi string SQL yang berisi perintah yang dapat dieksekusi : menggunakan pernyataan yang disiapkan tidak akan mengizinkannya.
Itu menambahkan metacharacter (alias konversi otomatis) untuk itu.
Ini membuatnya lebih aman.
Injeksi SQL: ketika pengguna memiliki kesempatan untuk memasukkan sesuatu yang bisa menjadi bagian dari pernyataan sql
Sebagai contoh:
String query = “INSERT INTO students VALUES ('” + user + “')”
saat pengguna memasukkan “Robert '); Siswa DROP TABLE; - ”sebagai input, menyebabkan injeksi SQL
Bagaimana pernyataan siap mencegah hal ini?
String query = “INSERT INTO students VALUES ('” + “: name” + “')”
parameter.addValue ("nama", pengguna);
=> ketika pengguna memasukkan lagi “Robert '); Siswa DROP TABLE; - “, string input dikompilasi sebelumnya pada driver sebagai nilai literal dan saya kira itu dapat dicor seperti:
CAST ('Robert'); Siswa DROP TABLE; - 'AS varchar (30))
Jadi pada akhirnya, string akan dimasukkan secara harfiah sebagai nama ke tabel.
http://blog.linguiming.com/index.php/2018/01/10/why-prepared-statement-avoids-sql-injection/
CAST(‘Robert’);
dari CAST(‘Robert’); DROP TABLE students; –‘ AS varchar(30))
akan rusak, maka itu akan melanjutkan untuk menjatuhkan tabel jika itu masalahnya. Itu menghentikan injeksi, jadi saya yakin contoh ini tidak cukup lengkap untuk menjelaskan skenario.
PreparedStatement:
1) Prekompilasi dan cache sisi DB dari pernyataan SQL mengarah pada eksekusi yang lebih cepat secara keseluruhan dan kemampuan untuk menggunakan kembali pernyataan SQL yang sama dalam batch.
2) Pencegahan otomatis serangan injeksi SQL dengan pelarian bawaan dari tanda kutip dan karakter khusus lainnya. Perhatikan bahwa ini mengharuskan Anda menggunakan salah satu metode PreparedStatement setXxx () untuk menyetel nilainya.
Seperti yang dijelaskan dalam posting ini , filePreparedStatement
sendirian tidak membantu Anda jika Anda masih menggabungkan String.
Misalnya, satu penyerang nakal masih dapat melakukan hal berikut:
Tidak hanya SQL, bahkan JPQL atau HQL dapat dikompromikan jika Anda tidak menggunakan parameter bind.
Intinya, Anda tidak boleh menggunakan penggabungan string saat membuat pernyataan SQL. Gunakan API khusus untuk tujuan itu:
Dalam Pernyataan Disiapkan, pengguna dipaksa untuk memasukkan data sebagai parameter. Jika pengguna memasukkan beberapa pernyataan rentan seperti DROP TABLE atau SELECT * FROM USERS maka data tidak akan terpengaruh karena ini akan dianggap sebagai parameter pernyataan SQL