Idenya sangat sederhana - permintaan dan data dikirim ke server database secara terpisah .
Itu saja.
Akar masalah injeksi SQL adalah dalam pencampuran kode dan data.
Faktanya, permintaan SQL kami adalah program yang sah . Dan kami membuat program semacam itu secara dinamis, menambahkan beberapa data dengan cepat. Dengan demikian, data dapat mengganggu kode program dan bahkan mengubahnya, karena setiap contoh injeksi SQL menunjukkannya (semua contoh dalam PHP / Mysql):
$expected_data = 1;
$query = "SELECT * FROM users where id=$expected_data";
akan menghasilkan permintaan reguler
SELECT * FROM users where id=1
sementara kode ini
$spoiled_data = "1; DROP TABLE users;"
$query = "SELECT * FROM users where id=$spoiled_data";
akan menghasilkan urutan berbahaya
SELECT * FROM users where id=1; DROP TABLE users;
Ini berfungsi karena kita menambahkan data secara langsung ke badan program dan itu menjadi bagian dari program, sehingga data dapat mengubah program, dan tergantung pada data yang dikirimkan, kita akan memiliki output reguler atau tabel users
dihapus.
Sementara dalam hal pernyataan yang disiapkan kami tidak mengubah program kami, itu tetap utuh
Itulah intinya.
Kami mengirim program ke server terlebih dahulu
$db->prepare("SELECT * FROM users where id=?");
di mana data diganti oleh beberapa variabel yang disebut parameter atau placeholder.
Perhatikan bahwa permintaan yang sama persis dikirimkan ke server, tanpa ada data di dalamnya! Dan kemudian kami mengirimkan data dengan permintaan kedua , yang pada dasarnya dipisahkan dari permintaan itu sendiri:
$db->execute($data);
jadi itu tidak dapat mengubah program kami dan membahayakan.
Cukup sederhana - bukan?
Satu-satunya hal yang harus saya tambahkan adalah selalu dihilangkan dalam setiap manual:
Pernyataan yang disiapkan hanya dapat melindungi literal data , tetapi tidak dapat digunakan dengan bagian kueri lainnya.
Jadi, begitu kita harus menambahkan, katakanlah, pengidentifikasi dinamis - nama bidang, misalnya - pernyataan yang disiapkan tidak dapat membantu kita. Saya sudah menjelaskan masalah ini baru-baru ini , jadi saya tidak akan mengulangi lagi.
$spoiled_data = "1; DROP TABLE users;"
->$query = "SELECT * FROM users where id=$spoiled_data";
, dibandingkan dengan:$db->prepare("SELECT * FROM users where id=?");
->$data = "1; DROP TABLE users;"
->$db->execute($data);
. Bukankah mereka akan melakukan hal yang sama?Berikut ini SQL untuk menyiapkan contoh:
Kelas Inject rentan terhadap injeksi SQL. Kueri ditempelkan secara dinamis bersama dengan input pengguna. Maksud kueri adalah untuk menunjukkan informasi tentang Bob. Baik gaji atau bonus, berdasarkan input pengguna. Tetapi pengguna jahat memanipulasi input yang merusak kueri dengan menempel pada persamaan 'atau benar' dengan klausa where sehingga semuanya dikembalikan, termasuk informasi tentang Aaron yang seharusnya disembunyikan.
Menjalankan ini, kasus pertama adalah dengan penggunaan normal, dan yang kedua dengan suntikan berbahaya:
Anda seharusnya tidak membangun pernyataan SQL Anda dengan rangkaian input pengguna. Tidak hanya itu rentan terhadap injeksi, tetapi memiliki implikasi caching pada server juga (pernyataan berubah, jadi lebih kecil kemungkinannya untuk mendapatkan cache pernyataan SQL hit sedangkan contoh bind selalu menjalankan pernyataan yang sama).
Berikut adalah contoh Binding untuk menghindari injeksi semacam ini:
Menjalankan ini dengan input yang sama seperti contoh sebelumnya menunjukkan kode berbahaya tidak berfungsi karena tidak ada jenis pembayaran yang cocok dengan string itu:
sumber
PREPARE
membuat pernyataan bernama tetap yang sudah diuraikan (yaitu pernyataan tidak akan berubah lagi terlepas dari input) sementaraEXECUTE
akan menjalankan pernyataan bernama mengikat parameter. KarenaPREPARE
hanya memiliki durasi sesi, sepertinya memang dimaksudkan untuk alasan kinerja, bukan untuk mencegah injeksi melalui skrip psql. Untuk akses psql, bisa memberikan izin ke prosedur tersimpan dan mengikat parameter dalam procs.Pada dasarnya, dengan pernyataan yang sudah disiapkan, data yang masuk dari peretas potensial diperlakukan sebagai data - dan tidak mungkin dicampur dengan SQL aplikasi Anda dan / atau ditafsirkan sebagai SQL (yang dapat terjadi ketika data yang disalurkan ditempatkan langsung ke dalam Anda aplikasi SQL).
Ini karena pernyataan yang disiapkan "menyiapkan" kueri SQL terlebih dahulu untuk menemukan rencana kueri yang efisien, dan mengirimkan nilai aktual yang mungkin datang dari formulir nanti - pada saat itu kueri sebenarnya dieksekusi.
Info hebat lainnya di sini:
Pernyataan yang disiapkan dan Injeksi SQL
sumber
Saya membaca jawaban dan masih merasa perlu menekankan poin kunci yang menerangi esensi Pernyataan Disiapkan. Pertimbangkan dua cara untuk menanyakan basis data seseorang di mana input pengguna terlibat:
Pendekatan Naif
Satu menggabungkan input pengguna dengan beberapa string SQL parsial untuk menghasilkan pernyataan SQL. Dalam hal ini pengguna dapat menanamkan perintah SQL berbahaya, yang kemudian akan dikirim ke database untuk dieksekusi.
Misalnya, input pengguna jahat dapat menyebabkan
SQLString
sama dengan"SELECT * FROM CUSTOMERS WHERE NAME='James';DROP TABLE CUSTOMERS;'
Karena pengguna jahat,
SQLString
berisi 2 pernyataan, di mana pernyataan ke-2 ("DROP TABLE CUSTOMERS"
) akan membahayakan.Pernyataan Disiapkan
Dalam hal ini, karena pemisahan kueri & data, input pengguna tidak pernah diperlakukan sebagai pernyataan SQL, dan karenanya tidak pernah dieksekusi . Karena alasan inilah, setiap kode SQL berbahaya yang disuntikkan tidak akan membahayakan. Jadi
"DROP TABLE CUSTOMERS"
tidak akan pernah dieksekusi dalam kasus di atas.Singkatnya, dengan pernyataan yang dipersiapkan kode berbahaya yang diperkenalkan melalui input pengguna tidak akan dieksekusi!
sumber
Saat Anda membuat dan mengirim pernyataan yang disiapkan ke DBMS, itu disimpan sebagai query SQL untuk dieksekusi.
Anda kemudian mengikat data Anda ke kueri sehingga DBMS menggunakan data itu sebagai parameter kueri untuk eksekusi (parameterisasi). DBMS tidak menggunakan data yang Anda ikat sebagai tambahan untuk permintaan SQL yang sudah dikompilasi; itu hanya data.
Ini berarti pada dasarnya tidak mungkin untuk melakukan injeksi SQL menggunakan pernyataan yang disiapkan. Sifat pernyataan yang disiapkan dan hubungannya dengan DBMS mencegah hal ini.
sumber
Dalam SQL Server , menggunakan pernyataan yang disiapkan pasti injeksi-bukti karena parameter input tidak membentuk kueri. Ini berarti bahwa permintaan yang dieksekusi bukanlah permintaan yang dinamis. Contoh pernyataan rentan injeksi SQL.
Sekarang jika nilai dalam variabel nama pengguna adalah sesuatu seperti 'atau 1 = 1 -, kueri ini sekarang menjadi:
Dan sisanya dikomentari setelah itu
--
, sehingga tidak pernah dieksekusi dan dilewati dengan menggunakan contoh pernyataan yang disiapkan seperti di bawah ini.Jadi sebenarnya Anda tidak dapat mengirim parameter lain, sehingga menghindari injeksi SQL ...
sumber
Frasa kuncinya adalah
need not be correctly escaped
. Itu berarti Anda tidak perlu khawatir tentang orang yang mencoba melempar tanda hubung, apostrof, kutipan, dll ...Itu semua ditangani untuk Anda.
sumber
Mari kita asumsikan Anda memilikinya di Servlet Anda benar. Jika seseorang yang jahat memberikan nilai buruk untuk 'filter', Anda mungkin meretas basis data Anda.
sumber
Root Cause # 1 - Masalah Pembatas
Sql injeksi dimungkinkan karena kami menggunakan tanda kutip untuk membatasi string dan juga menjadi bagian dari string, sehingga tidak mungkin untuk menafsirkannya kadang-kadang. Jika kami memiliki pembatas yang tidak dapat digunakan dalam data string, injeksi sql tidak akan pernah terjadi. Memecahkan masalah pembatas menghilangkan masalah injeksi sql. Query struktur melakukan itu.
Root Cause # 2 - Sifat Manusia, Orang Licik dan Beberapa Orang Licik Berbahaya Dan Semua Orang Membuat Kesalahan
Penyebab utama injeksi sql adalah sifat manusia. Orang, termasuk programmer, membuat kesalahan. Ketika Anda membuat kesalahan pada kueri terstruktur, itu tidak membuat sistem Anda rentan terhadap injeksi sql. Jika Anda tidak menggunakan kueri terstruktur, kesalahan dapat menghasilkan kerentanan injeksi sql.
Bagaimana kueri terstruktur menyelesaikan akar penyebab SQL Injection
Pertanyaan Terstruktur Memecahkan Masalah Pembatas, dengan menempatkan perintah sql dalam satu pernyataan dan menempatkan data dalam pernyataan pemrograman terpisah. Pernyataan pemrograman menciptakan pemisahan yang dibutuhkan.
Kueri terstruktur membantu mencegah kesalahan manusia membuat lubang keamanan kritis. Berkenaan dengan manusia membuat kesalahan, injeksi sql tidak dapat terjadi ketika permintaan struktur digunakan. Ada beberapa cara untuk mencegah injeksi sql yang tidak melibatkan kueri terstruktur, tetapi kesalahan manusia normal dalam pendekatan itu biasanya mengarah pada setidaknya beberapa paparan injeksi sql. Kueri Terstruktur gagal aman dari injeksi sql. Anda dapat membuat semua kesalahan di dunia, hampir, dengan kueri terstruktur, sama seperti pemrograman lainnya, tetapi tidak ada yang dapat Anda buat dapat diubah menjadi sistem yang diambil alih dengan injeksi sql. Itu sebabnya orang suka mengatakan ini adalah cara yang tepat untuk mencegah injeksi sql.
Jadi, begitulah, penyebab injeksi sql dan kueri terstruktur alam yang membuatnya tidak mungkin ketika digunakan.
sumber