Pertanyaan Bagaimana cara injeksi SQL dari komik "XKCD karya Bobby Tables"?


Hanya melihat:

XKCD Strip (Sumber: https://xkcd.com/327/)

Apa yang dilakukan SQL ini:

Robert'); DROP TABLE STUDENTS; --

Saya tahu keduanya ' dan -- adalah untuk komentar, tetapi tidak kata DROP mendapat komentar juga karena ini adalah bagian dari garis yang sama?


984
2017-12-01 21:50


asal


Jawaban:


Ini menjatuhkan meja siswa.

Kode asli dalam program sekolah mungkin terlihat seperti itu

q = "INSERT INTO Students VALUES ('" + FNMName.Text + "', '" + LName.Text + "')";

Ini adalah cara naif untuk menambahkan input teks ke dalam query, dan itu sangat buruk, seperti yang akan Anda lihat.

Setelah nilai dari nama depan, kotak teks nama tengah FNMName.Text (yang mana Robert'); DROP TABLE STUDENTS; --) dan kotak teks nama belakang LName.Text (sebut saja Derper) digabung dengan sisa kueri, hasilnya sekarang benar-benar dua pertanyaan dipisahkan oleh terminator pernyataan (titik koma). Kueri kedua telah disuntikkan menjadi yang pertama. Ketika kode mengeksekusi query ini terhadap database, itu akan terlihat seperti ini

INSERT INTO Students VALUES ('Robert'); DROP TABLE Students; --', 'Derper')

yang, dalam bahasa Inggris biasa, secara kasar diterjemahkan ke dua kueri:

Tambahkan catatan baru ke tabel Siswa dengan nilai Nama 'Robert'

dan

Hapus tabel Siswa

Semuanya melewati pertanyaan kedua adalah ditandai sebagai komentar: --', 'Derper')

Itu ' di nama siswa bukan komentar, itu penutupnya pemisah string. Karena nama siswa adalah string, dibutuhkan secara sintaksis untuk menyelesaikan kueri hipotetis. Serangan injeksi hanya bekerja ketika permintaan SQL mereka menyuntikkan hasil dalam SQL yang valid.

Diedit lagi sesuai dan04komentar cerdik


1018
2017-12-01 21:55



Katakanlah nama itu digunakan dalam variabel, $Name. Anda kemudian menjalankan kueri ini:

INSERT INTO Students VALUES ( '$Name' )

Kode tersebut secara keliru menempatkan apa pun yang diberikan pengguna sebagai variabel. Anda ingin SQL menjadi:

INSERT INTO Students VALUES ('Robert Tables`)

Tetapi pengguna yang pandai dapat menyediakan apa pun yang mereka inginkan:

INSERT INTO Students VALUES ('Robert '); Siswa DROP TABLE; -')

Apa yang Anda dapatkan adalah:

INSERT INTO Students VALUES ( 'Robert' );  DROP TABLE STUDENTS; --' )

Itu -- hanya komentar sisa baris.


546
2017-09-14 10:12



Seperti yang telah ditunjukkan oleh orang lain, the '); menutup pernyataan asli dan kemudian pernyataan kedua berikut. Kebanyakan kerangka kerja, termasuk bahasa seperti PHP, memiliki pengaturan keamanan default sekarang yang tidak mengijinkan beberapa pernyataan dalam satu string SQL. Di PHP, misalnya, Anda hanya dapat menjalankan beberapa pernyataan dalam satu string SQL dengan menggunakan mysqli_multi_query fungsi.

Anda dapat, bagaimanapun, memanipulasi pernyataan SQL yang ada melalui injeksi SQL tanpa harus menambahkan pernyataan kedua. Katakanlah Anda memiliki sistem login yang memeriksa nama pengguna dan kata sandi dengan pilihan sederhana ini:

$query="SELECT * FROM users WHERE username='" . $_REQUEST['user'] . "' and (password='".$_REQUEST['pass']."')";
$result=mysql_query($query);

Jika Anda berikan peter sebagai nama pengguna dan secret sebagai kata sandi, string SQL yang dihasilkan akan terlihat seperti ini:

SELECT * FROM users WHERE username='peter' and (password='secret')

Semuanya baik. Sekarang bayangkan Anda memberikan string ini sebagai kata sandi:

' OR '1'='1

Maka string SQL yang dihasilkan akan menjadi ini:

SELECT * FROM users WHERE username='peter' and (password='' OR '1'='1')

Itu akan memungkinkan Anda untuk masuk ke akun mana pun tanpa mengetahui kata sandinya. Jadi Anda tidak perlu dapat menggunakan dua pernyataan untuk menggunakan injeksi SQL, meskipun Anda dapat melakukan lebih banyak hal yang merusak jika Anda dapat menyediakan beberapa pernyataan.


145
2017-12-01 22:01



Tidak, ' bukan komentar dalam SQL, tapi pembatas.

Ibu menduga programmer basis data membuat permintaan seperti:

INSERT INTO 'students' ('first_name', 'last_name') VALUES ('$firstName', '$lastName');

(misalnya) untuk menambah siswa baru, di mana $xxx isi variabel diambil langsung dari bentuk HTML, tanpa memeriksa format atau melarikan karakter khusus.

Jadi jika $firstName mengandung Robert'); DROP TABLE students; -- program database akan mengeksekusi permintaan berikut langsung pada DB:

INSERT INTO 'students' ('first_name', 'last_name') VALUES ('Robert'); DROP TABLE students; --', 'XKCD');

yaitu. itu akan mengakhiri pernyataan insert awal, mengeksekusi kode berbahaya apa pun yang diinginkan oleh cracker, kemudian mengomentari sisa kode apa pun yang ada.

Mmm, saya terlalu lambat, saya sudah melihat 8 jawaban sebelum saya di band oranye ... :-) Sebuah topik yang populer, sepertinya.


68
2017-09-26 20:20



TL; DR

- Aplikasi ini menerima masukan, dalam hal ini 'Nancy', tanpa berusaha
- membersihkan input, seperti dengan mengeluarkan karakter khusus
school => INSERT INTO students VALUES ('Nancy');
INSERT 0 1

- Injeksi SQL terjadi ketika input ke dalam perintah database dimanipulasi
- menyebabkan server database mengeksekusi SQL sewenang-wenang
school => INSERT INTO students VALUES ('Robert'); Siswa DROP TABLE; - ');
INSERT 0 1
DROP TABLE

- Catatan siswa sekarang hilang - itu bisa menjadi lebih buruk!
sekolah => PILIH * DARI siswa;
KESALAHAN: hubungan "siswa" tidak ada
LINE 1: SELECT * FROM students;
                      ^

Ini menjatuhkan (menghapus) tabel siswa.

(Semua contoh kode dalam jawaban ini dijalankan pada server basis data PostgreSQL 9.1.2.)

Untuk memperjelas apa yang terjadi, coba ini dengan tabel sederhana yang hanya berisi bidang nama dan tambahkan satu baris:

school => CREATE TABLE students (beri nama TEXT PRIMARY KEY);
PEMBERITAHUAN: BUAT TABLE / PRIMARY KEY akan membuat indeks implisit "students_pkey" untuk tabel "siswa"
BUAT TABEL
school => INSERT INTO students VALUES ('John');
INSERT 0 1

Mari kita asumsikan aplikasi menggunakan SQL berikut untuk memasukkan data ke dalam tabel:

INSERT INTO students VALUES ('foobar');

Menggantikan foobar dengan nama sebenarnya dari siswa. Operasi insert normal akan terlihat seperti ini:

- Masukan: Nancy
school => INSERT INTO students VALUES ('Nancy');
INSERT 0 1

Saat kami membuat kueri tabel, kami mendapatkan ini:

sekolah => PILIH * DARI siswa;
 nama
-------
 John
 Nancy
(2 rows)

Apa yang terjadi ketika kami memasukkan nama Little Bobby Tables ke dalam tabel?

- Masukan: Robert '); Siswa DROP TABLE; -
school => INSERT INTO students VALUES ('Robert'); Siswa DROP TABLE; - ');
INSERT 0 1
DROP TABLE

Injeksi SQL di sini adalah hasil dari nama siswa yang mengakhiri pernyataan dan termasuk yang terpisah DROP TABLEperintah; dua tanda pisah pada akhir input dimaksudkan untuk mengomentari kode yang tersisa yang akan menyebabkan kesalahan. Baris terakhir dari output menegaskan bahwa server database telah menjatuhkan tabel.

Sangat penting untuk memperhatikan bahwa selama INSERT operasi aplikasi tidak memeriksa input untuk setiap karakter khusus, dan karena itu memungkinkan input acak untuk dimasukkan ke dalam perintah SQL. Ini berarti bahwa pengguna jahat dapat menyisipkan, ke dalam bidang yang biasanya ditujukan untuk masukan pengguna, simbol khusus seperti tanda kutip bersama dengan kode SQL acak menyebabkan sistem basis data mengeksekusinya, maka SQLinjeksi.

Hasil?

sekolah => PILIH * DARI siswa;
KESALAHAN: hubungan "siswa" tidak ada
LINE 1: SELECT * FROM students;
                      ^

Injeksi SQL adalah basis data yang setara dengan remote eksekusi kode arbitrer kerentanan dalam sistem operasi atau aplikasi. Dampak potensial dari serangan injeksi SQL yang sukses tidak dapat diremehkan - tergantung pada sistem basis data dan konfigurasi aplikasi, ini dapat digunakan oleh penyerang untuk menyebabkan kehilangan data (seperti dalam kasus ini), mendapatkan akses tidak sah ke data, atau bahkan mengeksekusi kode arbitrer pada mesin host itu sendiri.

Seperti yang dicatat oleh komik XKCD, salah satu cara melindungi terhadap serangan injeksi SQL adalah untuk membersihkan input database, seperti dengan mengeluarkan karakter khusus, sehingga mereka tidak dapat memodifikasi perintah SQL yang mendasari dan oleh karena itu tidak dapat menyebabkan eksekusi kode SQL acak. Jika Anda menggunakan permintaan parameter, seperti dengan menggunakan SqlParameter di ADO.NET, input akan, minimal, secara otomatis dibersihkan untuk menjaga terhadap injeksi SQL.

Namun, input sanitasi pada tingkat aplikasi mungkin tidak menghentikan teknik injeksi SQL yang lebih canggih. Sebagai contoh, ada cara untuk menghindari mysql_real_escape_string Fungsi PHP. Untuk perlindungan tambahan, banyak dukungan sistem basis data pernyataan siap. Jika diimplementasikan dengan benar di backend, pernyataan siap dapat membuat injeksi SQL tidak mungkin dengan memperlakukan input data sebagai semantically terpisah dari sisa perintah.


33
2017-12-01 21:56



Katakan Anda dengan naif menulis metode pembuatan siswa seperti ini:

void createStudent(String name) {
    database.execute("INSERT INTO students (name) VALUES ('" + name + "')");
}

Dan seseorang memasuki nama itu Robert'); DROP TABLE STUDENTS; --

Apa yang dijalankan di database adalah kueri ini:

INSERT INTO students (name) VALUES ('Robert'); DROP TABLE STUDENTS --')

Titik koma mengakhiri perintah insert dan memulai yang lain; - mengomentari sisa baris. Perintah DROP TABLE dijalankan ...

Inilah sebabnya mengapa mengikat parameter adalah hal yang baik.


27
2017-12-01 22:03



Kutipan tunggal adalah awal dan akhir string. Tanda titik koma adalah akhir dari sebuah pernyataan. Jadi jika mereka melakukan pilihan seperti ini:

Select *
From Students
Where (Name = '<NameGetsInsertedHere>')

SQL akan menjadi:

Select *
From Students
Where (Name = 'Robert'); DROP TABLE STUDENTS; --')
--             ^-------------------------------^

Pada beberapa sistem, select akan berlari pertama diikuti oleh drop pernyataan! Pesannya adalah: DONT EMBED VALUES INTO YOUR SQL. Alih-alih menggunakan parameter!


24
2017-12-01 21:53