Keamanan MongoDB tidak sepenuhnya dijamin hanya dengan mengonfigurasi sertifikat otentikasi atau mengenkripsi data. Beberapa penyerang akan "berusaha lebih keras" dengan bermain dengan parameter yang diterima dalam permintaan HTTP yang digunakan sebagai bagian dari proses kueri database.
Database SQL adalah yang paling rentan terhadap jenis serangan ini, tetapi injeksi eksternal juga dimungkinkan dalam DBM NoSQL seperti MongoDB. Dalam kebanyakan kasus, injeksi eksternal terjadi sebagai akibat dari rangkaian string yang tidak aman saat membuat kueri.
Apa itu Serangan Injeksi Eksternal?
Injeksi kode pada dasarnya mengintegrasikan data yang tidak divalidasi (vektor tak tanggung-tanggung) ke dalam program yang rentan yang ketika dijalankan, menyebabkan akses yang merusak ke database Anda; mengancam keselamatannya.
Saat variabel yang tidak bersih diteruskan ke kueri MongoDB, variabel tersebut merusak struktur orientasi kueri dokumen dan terkadang dieksekusi sebagai kode javascript itu sendiri. Ini sering terjadi ketika meneruskan props langsung dari modul body-parser untuk server Nodejs. Oleh karena itu, penyerang dapat dengan mudah memasukkan objek Js tempat Anda mengharapkan string atau angka, sehingga mendapatkan hasil yang tidak diinginkan atau dengan memanipulasi data Anda.
Pertimbangkan data di bawah ini dalam koleksi siswa.
{username:'John Doc', email:'[email protected]', age:20},
{username:'Rafael Silver', email:'[email protected]', age:30},
{username:'Kevin Smith', email:'[email protected]', age:22},
{username:'Pauline Wagu', email:'[email protected]', age:23}
Misalnya program Anda harus mengambil semua siswa yang usianya sama dengan 20, Anda akan menulis kode seperti ini...
app.get(‘/:age’, function(req, res){
db.collections(“students”).find({age: req.params.age});
})
Anda akan mengirimkan objek JSON dalam permintaan http Anda sebagai
{age: 20}
Ini akan mengembalikan semua siswa yang usianya sama dengan 20 sebagai hasil yang diharapkan dan dalam hal ini hanya {username:'John Doc', email:'[email protected]', age:20} .
Sekarang katakanlah penyerang mengirimkan objek alih-alih nomor yaitu {‘$gt:0’};
Kueri yang dihasilkan adalah:
db.collections(“siswa”).find({umur:{‘$gt:0’}); yang merupakan kueri valid yang setelah dieksekusi akan menampilkan semua siswa dalam koleksi tersebut. Penyerang memiliki kesempatan untuk bertindak atas data Anda sesuai dengan niat jahat mereka. Dalam kebanyakan kasus, penyerang menyuntikkan objek kustom yang berisi perintah MongoDB yang memungkinkan mereka mengakses dokumen Anda tanpa prosedur yang benar.
Beberapa perintah MongoDB mengeksekusi kode Javascript di dalam mesin database, yang berpotensi menimbulkan risiko bagi data Anda. Beberapa dari perintah ini adalah '$where', '$group' dan 'mapReduce'. Untuk versi sebelum MongoDB 2.4, kode Js memiliki akses ke objek db dari dalam kueri.
Perlindungan Naitive MongoDB
MongoDB menggunakan data BSON (Binary JSON) untuk kueri dan dokumennya, tetapi dalam beberapa kasus ia dapat menerima ekspresi JSON dan Js yang tidak bersambung (seperti yang disebutkan di atas). Sebagian besar data yang dikirimkan ke server dalam format string dan dapat dimasukkan langsung ke kueri MongoDB. MongoDB tidak mengurai datanya, oleh karena itu menghindari potensi risiko yang mungkin timbul dari integrasi parameter langsung.
Jika API melibatkan penyandian data dalam teks yang diformat dan teks tersebut perlu diuraikan, ini berpotensi menimbulkan ketidaksepakatan antara pemanggil server dan penerima database tentang bagaimana string tersebut akan diuraikan . Jika data secara tidak sengaja disalahartikan sebagai metadata, skenario tersebut berpotensi menimbulkan ancaman keamanan terhadap data Anda.
Contoh Injeksi Eksternal MongoDB dan Cara Menanganinya
Mari kita perhatikan data di bawah ini dalam koleksi siswa.
{username:'John Doc', password: ‘16djfhg’, email:'[email protected]', age:20},
{username:'Rafael Silver',password: ‘djh’, email:'[email protected]', age:30},
{username:'Kevin Smith', password: ‘16dj’, email:'[email protected]', age:22},
{username:'Pauline Wagu', password: ‘g6yj’, email:'[email protected]', age:23}
Injeksi Menggunakan Operator $ne (tidak sama)
Jika saya ingin mengembalikan dokumen dengan nama pengguna dan kata sandi yang diberikan dari permintaan, kodenya adalah:
app.post('/students, function (req, res) {
var query = {
username: req.body.username,
password: req.body.password
}
db.collection(students).findOne(query, function (err, student) {
res(student);
});
});
Jika kami menerima permintaan di bawah
POST https://localhost/students HTTP/1.1
Content-Type: application/json
{
"username": {"$ne": null},
"password": {"$ne": null}
}
Kueri pasti akan mengembalikan siswa pertama dalam kasus ini karena nama pengguna dan sandinya tidak bernilai nol. Ini tidak sesuai dengan hasil yang diharapkan.
Untuk mengatasi ini, Anda dapat menggunakan:
modul mongo-sanitize yang menghentikan kunci apa pun yang dimulai dengan'$' agar tidak diteruskan ke mesin kueri MongoDB.
Instal modul terlebih dahulu
npm install mongo-sanitize
var sanitize = require(‘mongo-sanitize’);
var query = {
username: req.body.username,
password: req.body.password
}
Menggunakan luwak untuk memvalidasi bidang skema Anda sehingga jika mengharapkan string dan menerima objek, kueri akan memunculkan kesalahan. Dalam kasus kami di atas nilai nol akan diubah menjadi string “” yang secara harfiah tidak berdampak.
Injeksi Menggunakan Operator $where
Ini adalah salah satu operator yang paling berbahaya. Ini akan memungkinkan string untuk dievaluasi di dalam server itu sendiri. Misalnya, untuk mengambil siswa yang usianya di atas nilai Y, kuerinya adalah
var query = {
$where: “this.age > ”+req.body.age
}
db.collection(students).findOne(query, function (err, student) {
res(student);
});
Menggunakan modul sanitize tidak akan membantu dalam kasus ini jika kita memiliki '0; return true' karena hasilnya akan mengembalikan semua siswa daripada mereka yang usianya lebih besar dari beberapa nilai yang diberikan. Kemungkinan string lain yang dapat Anda terima adalah '\'; return \ ‘\’ ==\’’ atau this.email ==='';return '' ==''. Kueri ini akan mengembalikan semua siswa, bukan hanya siswa yang cocok dengan klausa.
Klausa $where harus sangat dihindari. Selain kemunduran yang diuraikan juga mengurangi kinerja karena tidak dioptimalkan untuk menggunakan indeks.
Ada juga kemungkinan besar melewatkan fungsi dalam klausa $where dan variabel tidak akan dapat diakses dalam lingkup MongoDB sehingga dapat mengakibatkan aplikasi Anda mogok. Yaitu
var query = {
$where: function() {
return this.age > setValue //setValue is not defined
}
}
Anda juga dapat menggunakan operator $eq, $lt, $lte, $gt, $gte.
Melindungi Diri Anda dari Injeksi Eksternal MongoDB
Berikut adalah tiga hal yang dapat Anda lakukan untuk menjaga diri Anda tetap terlindungi...
- Validasi data pengguna. Melihat kembali bagaimana ekspresi $where dapat digunakan untuk mengakses data Anda, disarankan untuk selalu memvalidasi apa yang dikirim pengguna ke server Anda.
- Gunakan konsep validator JSON untuk memvalidasi skema Anda bersama dengan modul luwak.
- Desain kueri Anda sedemikian rupa sehingga kode Js tidak memiliki akses penuh ke kode database Anda.
Kesimpulan
Injeksi eksternal juga dimungkinkan dengan MongoDB. Ini sering dikaitkan dengan data pengguna yang tidak divalidasi yang masuk ke kueri MongoDB. Itu selalu penting untuk mendeteksi dan mencegah injeksi NoSQL dengan menguji data apa pun yang mungkin diterima oleh server Anda. Jika diabaikan, hal ini dapat mengancam keamanan data pengguna. Prosedur yang paling penting adalah memvalidasi data Anda di semua lapisan yang terlibat.