A learning platform that lets students compose MongoDB queries has dropped Node.js’s vm module and now parses every query into an abstract syntax tree (AST) before execution. The change removes a sandbox that could be broken, protecting the backend from arbitrary code that a malformed string could inject.
Mengapa sandbox asli gagal
Implementasi pertama membungkus handle database aktif dalam panggilan vm.runInContext dan mencoba membatasi pengguna dengan ekspresi reguler (regular expression). Ia hanya mengizinkan nama metode seperti find atau aggregate; setiap pengenal (identifier) lainnya seharusnya disaring.
Dua kelemahan membuat pendekatan tersebut tidak aman:
- Penyaringan regex dapat dilewati. JavaScript memungkinkan kode menggunakan notasi kurung siku (
obj["constructor"]) untuk mengakses properti apa pun. Seorang penyerang dapat mengambil konstruktorFunction, membangun fungsi baru, dan menjalankan kode apa pun yang mereka pilih. Regex tidak pernah melihat akses properti yang mendasari karena sumbernya dapat ditulis ulang dengan cara yang tak terhitung jumlahnya. vmbukanlah batas keamanan. Dokumentasi Node menyatakan bahwavmmengisolasi objek global tetapi bukan seluruh proses. Dengan menyuntikkan koneksi database aktif ke dalam sandbox, kode di dalam konteks tersebut tetap memiliki kemampuan untuk memanggil metode apa pun pada koneksi tersebut, termasuk metode yang menulis atau menghapus data. Sandbox tersebut tidak menghentikan kode untuk memengaruhi proses host.
Solusi berbasis AST
Tim mengganti eksekusi kode dengan analisis statis. String kueri kini dimasukkan ke dalam parser acorn, yang menghasilkan AST—representasi pohon dari struktur sintaksis kode. AST diperiksa node demi node terhadap daftar putih (whitelist) yang ketat:
- Literal, array, dan objek hanya diizinkan jika muncul sebagai nilai biasa.
- Pemanggilan metode dibatasi pada set yang telah ditentukan sebelumnya (
find,sort,limit, dll.). Pemanggilan lainnya akan ditolak. - Akses properti terhitung (misalnya,
obj[expr]) atau tipe node apa pun yang tidak tercantum secara eksplisit akan memicu kegagalan seketika.
Karena parser bekerja pada pohon, bukan pada teks mentah, ia tidak dapat dikelabui oleh ejaan alternatif atau trik notasi kurung siku. Rantai konstruktor yang seharusnya lolos dari regex akan muncul sebagai node yang tidak dikenali dan ditolak sebelum kode apa pun dijalankan.
Apa artinya bagi keamanan
Desain baru ini mengikuti filosofi "tolak secara default" (deny by default):
- Tentukan apa yang diizinkan, bukan apa yang dilarang. Daftar putih berbasis teks tidak dapat mencakup segalanya; AST memiliki set tipe node yang terbatas, sehingga pemeriksaan menyeluruh menjadi layak dilakukan.
- Jangan pernah mengekspos sumber daya aktif di dalam sandbox. Mengirimkan handle database ke dalam konteks yang terisolasi memberikan kode sandbox jalur langsung ke backend. Pendekatan parser tidak pernah menyerahkan objek aktif ke kode pengguna; ia hanya mengekstrak maksud dari kueri tersebut.
- Validasi struktur, lalu eksekusi dengan aman. Setelah AST lolos validasi, platform menerjemahkan pemanggilan yang diizinkan ke dalam metode driver MongoDB yang sebenarnya menggunakan jalur kode tepercaya miliknya sendiri.
Hal yang perlu diperhatikan selanjutnya
- Audit setiap penggunaan
eval,new Function, atauvmdalam basis kode Anda. Bahkan daftar putih pun dapat disabotase oleh sifat dinamis JavaScript. - Gunakan parsing AST untuk kode buatan pengguna jika memungkinkan. Library seperti
acorn,esprima, ataubabel-parsermembuat transformasi ini menjadi mudah. - Batasi paparan objek aktif. Jika koneksi database, handle file, atau socket jaringan harus dapat dijangkau, bungkuslah dalam sebuah proxy yang hanya mengekspos metode minimal yang ingin Anda izinkan.
- Otomatisasi pengujian kasus tepi (edge cases). Hasilkan kueri yang menggunakan notasi kurung siku, kunci terhitung (computed keys), atau manipulasi prototipe untuk memverifikasi bahwa parser Anda menolaknya.
Kesimpulan
Mengandalkan vm.runInContext sebagai sandbox memberikan rasa aman yang palsu; filter regex tidak dapat mencakup sintaksis JavaScript yang fleksibel, dan sandbox tidak mengisolasi sumber daya proses. Mengurai input pengguna ke dalam AST dan membuat daftar putih hanya untuk node yang Anda pahami menyediakan penghalang konkret dan mudah dikelola yang menghentikan kode berbahaya sebelum dijalankan. Jika platform Anda mengizinkan pengguna menulis kode, gantilah eksekusi gaya eval dengan analisis statis hari ini.
