Mengenai banyak jawaban yang bermanfaat, saya berharap dapat menambah nilai pada utas ini.
Injeksi SQL adalah serangan yang dapat dilakukan melalui input pengguna (input yang diisi oleh pengguna dan kemudian digunakan di dalam kueri). Pola injeksi SQL adalah sintaks kueri yang benar sementara kita dapat menyebutnya: kueri buruk karena alasan buruk, dan kami berasumsi bahwa mungkin ada orang jahat yang mencoba untuk mendapatkan informasi rahasia (melewati kontrol akses) yang memengaruhi tiga prinsip keamanan (kerahasiaan) , integritas, dan ketersediaan).
Sekarang, poin kami adalah untuk mencegah ancaman keamanan seperti serangan injeksi SQL, pertanyaan yang diajukan (bagaimana mencegah serangan injeksi SQL menggunakan PHP), menjadi lebih realistis, penyaringan data atau membersihkan data input adalah kasus ketika menggunakan input data pengguna di dalam permintaan seperti itu, menggunakan PHP atau bahasa pemrograman lain tidak demikian, atau seperti yang direkomendasikan oleh lebih banyak orang untuk menggunakan teknologi modern seperti pernyataan yang disiapkan atau alat lain yang saat ini mendukung pencegahan injeksi SQL, apakah alat ini tidak tersedia lagi? Bagaimana Anda mengamankan aplikasi Anda?
Pendekatan saya terhadap injeksi SQL adalah: membersihkan data input pengguna sebelum mengirimnya ke database (sebelum menggunakannya di dalam permintaan apa pun).
Pemfilteran data untuk (mengonversi data yang tidak aman ke data yang aman)
Pertimbangkan bahwa PDO dan MySQLi tidak tersedia. Bagaimana Anda bisa mengamankan aplikasi Anda? Apakah Anda memaksa saya untuk menggunakannya? Bagaimana dengan bahasa lain selain PHP? Saya lebih suka memberikan gagasan umum karena dapat digunakan untuk perbatasan yang lebih luas, bukan hanya untuk bahasa tertentu.
- Pengguna SQL (membatasi hak pengguna): operasi SQL yang paling umum adalah (SELECT, UPDATE, INSERT), lalu, mengapa memberikan hak istimewa UPDATE kepada pengguna yang tidak memerlukannya? Misalnya, halaman login, dan pencarian hanya menggunakan SELECT, lalu, mengapa menggunakan pengguna DB di halaman ini dengan hak istimewa tinggi?
ATURAN: jangan membuat satu pengguna basis data untuk semua hak istimewa. Untuk semua operasi SQL, Anda dapat membuat skema seperti (deluser, selectuser, updateuser) sebagai nama pengguna untuk penggunaan yang mudah.
Lihat prinsip privilege paling tidak .
Pemfilteran data: sebelum membangun input pengguna kueri apa pun, harus divalidasi dan difilter. Untuk programmer, penting untuk mendefinisikan beberapa properti untuk setiap variabel input pengguna:
tipe data, pola data, dan panjang data . Bidang yang merupakan angka antara (x dan y) harus benar-benar divalidasi menggunakan aturan yang tepat, dan untuk bidang yang berupa string (teks): pola adalah kasusnya, misalnya, nama pengguna harus berisi hanya beberapa karakter, mari katakan [a-zA-Z0-9_-.]. Panjangnya bervariasi antara (x dan n) di mana x dan n (bilangan bulat, x <= n).
Aturan: membuat filter yang tepat dan aturan validasi adalah praktik terbaik bagi saya.
Gunakan alat lain: Di sini, saya juga akan setuju dengan Anda bahwa pernyataan yang disiapkan (permintaan parametrized) dan prosedur tersimpan. Kerugiannya di sini adalah cara-cara ini membutuhkan keterampilan tingkat lanjut yang tidak ada untuk sebagian besar pengguna. Ide dasar di sini adalah untuk membedakan antara permintaan SQL dan data yang digunakan di dalamnya. Kedua pendekatan dapat digunakan bahkan dengan data yang tidak aman, karena data input pengguna di sini tidak menambahkan apa pun ke permintaan asli, seperti (apa saja atau x = x).
Untuk informasi lebih lanjut, silakan baca Lembar Cheat Pencegahan Injeksi SQL OWASP .
Sekarang, jika Anda adalah pengguna tingkat lanjut, mulailah menggunakan pertahanan ini sesuka Anda, tetapi, untuk pemula, jika mereka tidak dapat dengan cepat menerapkan prosedur tersimpan dan menyiapkan pernyataan, lebih baik menyaring data input sebanyak yang mereka bisa.
Akhirnya, mari pertimbangkan bahwa pengguna mengirim teks ini di bawah alih-alih memasukkan nama pengguna:
[1] UNION SELECT IF(SUBSTRING(Password,1,1)='2',BENCHMARK(100000,SHA1(1)),0) User,Password FROM mysql.user WHERE User = 'root'
Input ini dapat diperiksa lebih awal tanpa pernyataan yang disiapkan dan prosedur tersimpan, tetapi untuk berada di sisi yang aman, menggunakannya dimulai setelah penyaringan dan validasi data pengguna.
Poin terakhir adalah mendeteksi perilaku tak terduga yang membutuhkan lebih banyak upaya dan kompleksitas; itu tidak disarankan untuk aplikasi web normal.
Perilaku tak terduga dalam input pengguna di atas adalah SELECT, UNION, IF, SUBSTRING, BENCHMARK, SHA, dan root. Setelah kata-kata ini terdeteksi, Anda dapat menghindari input.
PEMBARUAN 1:
Seorang pengguna berkomentar bahwa posting ini tidak berguna, OK! Inilah yang disediakan OWASP.ORG :
Pertahanan utama:
Opsi # 1: Penggunaan Pernyataan yang Disiapkan (Kueri Parameterized)
Opsi # 2: Penggunaan Prosedur yang Disimpan
Opsi # 3: Melarikan Diri dari Semua Input yang Disuplai Pengguna
Pertahanan tambahan:
Juga Menegakkan: Least Privilege
Juga Melakukan: Validasi Input Daftar Putih
Seperti yang Anda ketahui, mengklaim sebuah artikel harus didukung oleh argumen yang valid, setidaknya dengan satu referensi! Kalau tidak, itu dianggap sebagai serangan dan klaim buruk!
Pembaruan 2:
Dari manual PHP, PHP: Pernyataan Disiapkan - Manual :
Melarikan diri dan injeksi SQL
Variabel terikat akan lolos secara otomatis oleh server. Server memasukkan nilai yang diloloskan di tempat yang sesuai ke dalam templat pernyataan sebelum dieksekusi. Petunjuk harus disediakan ke server untuk jenis variabel terikat, untuk membuat konversi yang sesuai. Lihat fungsi mysqli_stmt_bind_param () untuk informasi lebih lanjut.
Pelolosan nilai secara otomatis di dalam server terkadang dianggap sebagai fitur keamanan untuk mencegah injeksi SQL. Tingkat keamanan yang sama dapat dicapai dengan pernyataan yang tidak disiapkan jika nilai input diloloskan dengan benar.
Pembaruan 3:
Saya membuat kasus uji untuk mengetahui bagaimana PDO dan MySQLi mengirim kueri ke server MySQL saat menggunakan pernyataan yang disiapkan:
PDO:
$user = "''1''"; // Malicious keyword
$sql = 'SELECT * FROM awa_user WHERE userame =:username';
$sth = $dbh->prepare($sql, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
$sth->execute(array(':username' => $user));
Log Kueri:
189 Query SELECT * FROM awa_user WHERE userame ='\'\'1\'\''
189 Quit
MySQLi:
$stmt = $mysqli->prepare("SELECT * FROM awa_user WHERE username =?")) {
$stmt->bind_param("s", $user);
$user = "''1''";
$stmt->execute();
Log Kueri:
188 Prepare SELECT * FROM awa_user WHERE username =?
188 Execute SELECT * FROM awa_user WHERE username ='\'\'1\'\''
188 Quit
Jelas bahwa pernyataan yang dipersiapkan juga melarikan diri dari data, tidak ada yang lain.
Seperti juga disebutkan dalam pernyataan di atas,
Pelolosan nilai secara otomatis di dalam server terkadang dianggap sebagai fitur keamanan untuk mencegah injeksi SQL. Tingkat keamanan yang sama dapat dicapai dengan pernyataan yang tidak disiapkan, jika nilai input diloloskan dengan benar
Oleh karena itu, ini membuktikan bahwa validasi data seperti intval()
ide yang baik untuk nilai integer sebelum mengirim permintaan apa pun. Selain itu, mencegah data pengguna jahat sebelum mengirim kueri adalah pendekatan yang benar dan valid .
Silakan lihat pertanyaan ini untuk lebih detail: PDO mengirimkan permintaan mentah ke MySQL sementara Mysqli mengirimkan permintaan yang sudah disiapkan, keduanya menghasilkan hasil yang sama
Referensi:
- Lembar Cheat Injeksi SQL
- Injeksi SQL
- Informasi keamanan
- Prinsip Keamanan
- Validasi data