Mencegah injeksi SQL di Node.js


88

Apakah mungkin untuk mencegah injeksi SQL di Node.js (sebaiknya dengan modul) dengan cara yang sama seperti PHP telah Mempersiapkan Pernyataan yang melindunginya.

Jika ya, bagaimana caranya? Jika tidak, apa saja contoh yang mungkin mengabaikan kode yang saya berikan (lihat di bawah).


Beberapa Konteks:

Saya membuat aplikasi web dengan back-end stack yang terdiri dari Node.js + MySql menggunakan modul node-mysql . Dari perspektif kegunaan, modul besar, tetapi belum diimplementasikan sesuatu yang mirip dengan PHP Laporan Disiapkan (meskipun aku sadar itu adalah pada todo ).

Dari pemahaman saya, implementasi PHP dari pernyataan yang disiapkan, antara lain, sangat membantu dalam pencegahan injeksi SQL. Saya khawatir, bagaimanapun, bahwa aplikasi node.js saya mungkin terbuka untuk serangan serupa, bahkan dengan string yang keluar disediakan secara default (seperti pada potongan kode di bawah).

node-mysql tampaknya menjadi konektor mysql paling populer untuk node.js, jadi saya bertanya-tanya apa yang mungkin dilakukan orang lain (jika ada) untuk memperhitungkan masalah ini - atau apakah itu bahkan masalah dengan node.js untuk memulai (tidak yakin bagaimana ini tidak terjadi, karena input sisi pengguna / klien terlibat).

Haruskah saya beralih ke node-mysql-native untuk saat ini, karena ini menyediakan pernyataan yang sudah disiapkan? Saya ragu-ragu untuk melakukan ini, karena tampaknya tidak seaktif node-mysql (meskipun itu mungkin berarti sudah selesai).

Berikut adalah potongan kode registrasi pengguna, yang menggunakan modul pembersih , bersama dengan sintaks seperti pernyataan node-mysql yang disiapkan (yang, seperti yang saya sebutkan di atas, melakukan pelolosan karakter), untuk mencegah skrip lintas situs dan injeksi sql, masing-masing:

// Prevent xss
var clean_user = sanitizer.sanitize(username);

// assume password is hashed already
var post = {Username: clean_user, Password: hash};

// This just uses connection.escape() underneath
var query = connection.query('INSERT INTO users SET ?', post,
   function(err, results)
   {
       // Can a Sql injection happen here?
   });

Jawaban:


60

The node-mysqlperpustakaan secara otomatis melakukan melarikan diri bila digunakan sebagai Anda sudah lakukan. Lihat https://github.com/felixge/node-mysql#escaping-query-values


3
Seperti yang disebutkan dalam posting saya, saya sadar bahwa pustaka tersebut lolos dari karakter, tetapi saya lebih khawatir tentang implikasi keamanan jika saya tidak beralih ke pustaka yang telah mengimplementasikan pernyataan yang disiapkan, yaitu apakah ada injeksi SQL yang dapat terjadi dengan apa Saya sedang melakukan?
funseiki

2
Karakter melarikan diri mencegah injeksi SQL. Injeksi terjadi ketika karakter tidak lolos, dan pengguna jahat dapat memanfaatkan ini untuk menutup kueri dan memulai yang baru untuk, katakanlah, jatuhkan tabel atau masukkan catatan palsu. Dengan karakter yang lolos, ini tidak mungkin. Wikipedia memiliki beberapa informasi tambahan tentang SQL Injection.
Michael Pratt

4
Tetapi apakah itu mencegah semua injeksi SQL? Jawaban ini tidak menyarankan (setidaknya untuk PHP + MySQL) dan menyiratkan bahwa Pernyataan Disiapkan PHP melakukannya. Sekali lagi, ini dalam konteks PHP.
funseiki

1
Menurut tautan Anda, itu hanya berfungsi pada versi MySQL yang kedaluwarsa. Saya tidak tahu apakah serangan itu berfungsi pada Node, tetapi sepertinya itu berkaitan dengan kerentanan PHP yang sangat spesifik, jadi firasat saya tidak. Saya tidak mengatakan sama sekali tidak ada kerentanan di node-mysql, tetapi sudah digunakan di banyak lingkungan produksi. Jika Anda masih khawatir tentang injeksi SQL, saya sarankan untuk mencobanya dan mencoba sesuatu seperti MongoDB - tidak dapat melakukan injeksi SQL jika Anda tidak menggunakan SQL.
Michael Pratt

1
Itu terlihat seperti itu dan rute MongoDB adalah poin yang bagus - meskipun desain saat ini akan cocok dengan skema relasional. Saya akan menunggu untuk melihat apakah ada orang lain yang memiliki wawasan tentang kerentanan keamanan - jika tidak, sepertinya konsensusnya hanya berpegang pada node-mysql
funseiki

12

Perpustakaan memiliki bagian di readme tentang melarikan diri. Ini Javascript-native, jadi saya tidak menyarankan beralih ke node-mysql-native . Dokumentasi menyatakan pedoman untuk melarikan diri ini:

Edit: node-mysql-native juga merupakan solusi Javascript murni.

  • Nomor tidak tersentuh
  • Boolean diubah menjadi true/ falsestring
  • Objek tanggal diubah menjadi YYYY-mm-dd HH:ii:ssstring
  • Buffer diubah menjadi string hex, misalnya X'0fa5'
  • String lolos dengan aman
  • Array diubah menjadi daftar, misalnya ['a', 'b']berubah menjadi'a', 'b'
  • Array bersarang diubah menjadi daftar yang dikelompokkan (untuk sisipan massal), misalnya [['a', 'b'], ['c', 'd']]berubah menjadi('a', 'b'), ('c', 'd')
  • Objek diubah menjadi key = 'val'pasangan. Objek bersarang dilemparkan ke string.
  • undefined/ nulldiubah menjadiNULL
  • NaNAku Infinitydibiarkan apa adanya. MySQL tidak mendukung ini, dan mencoba memasukkannya sebagai nilai akan memicu kesalahan MySQL sampai mereka menerapkan dukungan.

Ini memungkinkan Anda melakukan hal-hal seperti ini:

var userId = 5;
var query = connection.query('SELECT * FROM users WHERE id = ?', [userId], function(err, results) {
  //query.sql returns SELECT * FROM users WHERE id = '5'
});

Dan juga ini:

var post  = {id: 1, title: 'Hello MySQL'};
var query = connection.query('INSERT INTO posts SET ?', post, function(err, result) {
  //query.sql returns INSERT INTO posts SET `id` = 1, `title` = 'Hello MySQL'
});

Selain dari fungsi tersebut, Anda juga dapat menggunakan fungsi escape:

connection.escape(query);
mysql.escape(query);

Untuk menghindari pengenal kueri:

mysql.escapeId(identifier);

Dan sebagai tanggapan atas komentar Anda tentang pernyataan yang disiapkan:

Dari perspektif kegunaan, modul ini bagus, tetapi belum menerapkan sesuatu yang mirip dengan Pernyataan Disiapkan PHP.

Laporan siap berada di todo daftar untuk konektor ini, tetapi modul ini setidaknya memungkinkan Anda untuk menentukan format kustom yang bisa sangat mirip dengan pernyataan siap. Berikut contoh dari readme:

connection.config.queryFormat = function (query, values) {
  if (!values) return query;
  return query.replace(/\:(\w+)/g, function (txt, key) {
    if (values.hasOwnProperty(key)) {
      return this.escape(values[key]);
    }
    return txt;
  }.bind(this));
};

Ini mengubah format kueri koneksi sehingga Anda bisa menggunakan kueri seperti ini:

connection.query("UPDATE posts SET title = :title", { title: "Hello MySQL" });
//equivalent to
connection.query("UPDATE posts SET title = " + mysql.escape("Hello MySQL");

Terima kasih atas tanggapannya - Saya sadar akan gaya yang disiapkan. Namun, di bawahnya, karakter sedang di-escape. Lihat: "Namun, ini benar-benar hanya menggunakan koneksi yang sama.escape ()" . Sejauh tidak menggunakan node-mysql-native: inilah yang saya perjuangkan. Jika node-mysql-native mengimplementasikan pernyataan yang disiapkan dan implementasinya mencegah injeksi SQL, bukankah saya harus beralih sampai node-mysql memilikinya?
funseiki

Ini semacam pertanyaan tentang ayam dan telur. Saya tidak secara aktif mengembangkan driver saya karena kebanyakan orang menggunakan @ felixge's. Saya mungkin akan mencoba meluangkan waktu untuk mem-port pernyataan yang telah disiapkan ke node-mysql karena memang memberikan beberapa manfaat kinerja (dan berpotensi membuat suntikan sql lebih sulit). Jangan ragu untuk berkomentar / memposting masalah jika Anda memutuskan untuk mencobanya
Andrey Sidorov

1
@funseiki Saya yakin pernyataan yang disiapkan akan menjadi solusi terbaik, tetapi saya sangat yakin bahwa pelolosan akan mencegah injeksi SQL. Karena modulnya sendiri didukung oleh Joyent, modul tersebut aktif dan jelas diperiksa secara menyeluruh. Jika modul ini tidak siap untuk produksi, maka menurut saya modul tersebut tidak akan memiliki rata-rata 1000 unduhan / hari bulan lalu. Perhatikan bahwa node-mysql-native adalah 6 bulan sejak terakhir kali dikembangkan, dan node-mysql sangat aktif, dengan banyak orang yang mengerjakannya.
hexacyanide

@AndreySidorov Terima kasih atas komentarnya - jika saya berusaha mengatasinya, saya akan memposting pembaruan. Saya tidak berpikir itu akan terjadi dalam waktu dekat, karena sepertinya itu tidak akan menjadi binatang yang mudah ditangani (akan membutuhkan lebih banyak penelitian daripada yang saya miliki saat ini). Juga terima kasih telah membuat driver itu - kalian adalah alasan mengapa Node.js membuatnya mudah untuk menjalankan aplikasi dengan cepat
funseiki

@hexacyanide Karena node-mysql sangat populer, saya berharap saya bisa mendapatkan tanggapan dari anggota komunitas mengenai masalah keamanan yang mungkin mereka temui (atau cegah) serta argumen yang meyakinkan tentang mengapa pendekatan pelarian karakter saat ini aman cukup untuk kode mereka.
funseiki

12

Saya menyadari ini adalah posting yang lebih lama tetapi tampaknya jawaban tidak pernah ditandai jadi saya akan membuang ini ke sana.

Berkenaan dengan pengujian apakah modul yang Anda gunakan aman atau tidak, ada beberapa rute yang dapat Anda ambil. Saya akan membahas pro / kontra masing-masing sehingga Anda dapat membuat keputusan yang lebih tepat.

Saat ini tidak ada kerentanan apa pun untuk modul yang Anda gunakan, namun hal ini sering kali dapat menyebabkan rasa aman yang salah karena kemungkinan besar ada kerentanan yang saat ini mengeksploitasi paket modul / perangkat lunak yang Anda gunakan dan Anda tidak akan diberi tahu masalah sampai vendor menerapkan perbaikan / tambalan.

  1. Untuk terus mengetahui kerentanan, Anda harus mengikuti milis, forum, IRC & diskusi terkait peretasan lainnya. PRO: Anda sering kali menyadari potensi masalah dalam perpustakaan sebelum vendor diberi tahu atau telah mengeluarkan perbaikan / tambalan untuk memperbaiki kemungkinan serangan pada perangkat lunak mereka. CON: Ini bisa sangat memakan waktu dan sumber daya. Jika Anda melakukan rute ini, bot menggunakan umpan RSS, penguraian log (log obrolan IRC) dan atau scrapper web menggunakan frasa kunci (dalam hal ini node-mysql-native) dan pemberitahuan dapat membantu mengurangi waktu yang dihabiskan untuk mengontrol sumber daya ini.

  2. Buat fuzzer, gunakan fuzzer atau kerangka kerja kerentanan lainnya seperti metasploit , sqlMap , dll. Untuk membantu menguji masalah yang mungkin tidak dicari oleh vendor. PRO: Ini dapat terbukti menjadi metode yang pasti untuk memastikan ke tingkat yang dapat diterima apakah modul / perangkat lunak yang Anda terapkan aman untuk akses publik atau tidak. CON: Ini juga menjadi memakan waktu dan mahal. Masalah lain akan berasal dari kesalahan positif serta tinjauan tidak berpendidikan dari hasil di mana masalah berada tetapi tidak diperhatikan.

Benar-benar keamanan, dan keamanan aplikasi secara umum bisa sangat memakan waktu dan sumber daya. Satu hal yang akan selalu digunakan manajer adalah formula untuk menentukan efektivitas biaya (tenaga kerja, sumber daya, waktu, gaji, dll) dari melakukan dua opsi di atas.

Bagaimanapun, saya menyadari ini bukanlah jawaban 'ya' atau 'tidak' yang mungkin diharapkan tetapi saya tidak berpikir ada yang bisa memberikannya kepada Anda sampai mereka melakukan analisis perangkat lunak yang dimaksud.


3

Saya tahu bahwa pertanyaan ini sudah lama tetapi bagi siapa pun yang tertarik, Mysql-native sudah ketinggalan zaman sehingga menjadi MySQL2 yang merupakan modul baru yang dibuat dengan bantuan tim modul MySQL asli. Modul ini memiliki lebih banyak fitur dan saya pikir itu memiliki apa yang Anda inginkan karena telah menyiapkan pernyataan (dengan menggunakan.execute ()) seperti di PHP untuk keamanan lebih.

Ini juga sangat aktif (perubahan terakhir adalah dari 2-1 hari) Saya tidak mencobanya sebelumnya tetapi saya pikir itu yang Anda inginkan dan banyak lagi.


-1

Cara termudah adalah menangani semua interaksi database Anda dalam modulnya sendiri yang Anda ekspor ke rute Anda. Jika rute Anda tidak memiliki konteks database, maka SQL tetap tidak dapat menyentuhnya.


Itu tidak benar-benar menjawab pertanyaan OP tentang cara membersihkan.
Christopher
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.