Advertisement

Security Best Practices

Maksud

Dokumen ini dimaksudkan untuk memperluas model ancaman saat ini dan menyediakan panduan lengkap tentang cara mengamankan aplikasi Node.js.

Konten Dokumen

  • Praktik terbaik: Cara ringkas dan sederhana untuk melihat praktik terbaik. Kita dapat menggunakan isu ini atau panduan ini sebagai titik awal. Penting untuk dicatat bahwa dokumen ini khusus untuk Node.js, jika Anda mencari sesuatu yang luas, pertimbangkan Praktik Terbaik OSSF.
  • Penjelasan serangan: ilustrasikan dan dokumentasikan dalam bahasa Inggris sederhana dengan beberapa contoh kode (jika memungkinkan) dari serangan yang kami sebutkan dalam model ancaman.
  • Perpustakaan Pihak Ketiga: definisikan ancaman (serangan typosquatting, paket berbahaya...) dan praktik terbaik terkait dependensi modul node, dll...


Daftar Ancaman
Penolakan Layanan server HTTP (CWE-400)


Ini adalah serangan yang menyebabkan aplikasi menjadi tidak tersedia untuk tujuan yang dirancang karena cara aplikasi memproses permintaan HTTP yang masuk. Permintaan ini tidak harus dibuat dengan sengaja oleh pelaku jahat: klien yang salah konfigurasi atau bermasalah juga dapat mengirim pola permintaan ke server yang mengakibatkan penolakan layanan.

Permintaan HTTP diterima oleh server HTTP Node.js dan diserahkan ke kode aplikasi melalui pengendali permintaan yang terdaftar. Server tidak mengurai konten isi permintaan. Oleh karena itu, DoS apa pun yang disebabkan oleh konten isi setelah diserahkan ke pengendali permintaan bukanlah kerentanan di Node.js itu sendiri, karena merupakan tanggung jawab kode aplikasi untuk menanganinya dengan benar.

Pastikan bahwa WebServer menangani kesalahan soket dengan benar, misalnya, ketika server dibuat tanpa pengendali kesalahan, server tersebut akan rentan terhadap DoS

 import net from 'node:net';

const server = net.createServer(function (socket) {
  // socket.on('error', console.error) // this prevents the server to crash
  socket.write('Echo server\r\n');
  socket.pipe(socket);
});

server.listen(5000, '0.0.0.0');

 Jika permintaan yang salah dilakukan, server bisa mogok.

Contoh serangan DoS yang tidak disebabkan oleh konten permintaan adalah Slowloris. Dalam serangan ini, permintaan HTTP dikirim secara lambat dan terfragmentasi, satu fragmen dalam satu waktu. Hingga permintaan penuh dikirimkan, server akan menyimpan sumber daya yang didedikasikan untuk permintaan yang sedang berlangsung. Jika cukup banyak permintaan ini dikirim pada saat yang sama, jumlah koneksi bersamaan akan segera mencapai maksimum yang mengakibatkan penolakan layanan. Beginilah cara serangan bergantung bukan pada konten permintaan tetapi pada waktu dan pola permintaan yang dikirim ke server.

 

Mitigasi

  • Gunakan proxy terbalik untuk menerima dan meneruskan permintaan ke aplikasi Node.js. Proxy terbalik dapat menyediakan caching, penyeimbangan beban, daftar hitam IP, dll. yang mengurangi kemungkinan serangan DoS menjadi efektif.
  • Konfigurasikan batas waktu server dengan benar, sehingga koneksi yang tidak aktif atau permintaan yang datang terlalu lambat dapat diputus. Lihat batas waktu yang berbeda di http.Server, khususnya headersTimeout, requestTimeout, timeout, dan keepAliveTimeout.
  • Batasi jumlah soket terbuka per host dan secara total. Lihat dokumen http, khususnya agent.maxSockets, agent.maxTotalSockets, agent.maxFreeSockets, dan server.maxRequestsPerSocket.

 

 DNS Rebinding (CWE-346)

Ini adalah serangan yang dapat menargetkan aplikasi Node.js yang dijalankan dengan inspektur debugging yang diaktifkan menggunakan sakelar --inspect.

Karena situs web yang dibuka di browser web dapat membuat permintaan WebSocket dan HTTP, situs web tersebut dapat menargetkan inspektur debugging yang berjalan secara lokal. Hal ini biasanya dicegah oleh kebijakan asal yang sama yang diterapkan oleh browser modern, yang melarang skrip menjangkau sumber daya dari asal yang berbeda (artinya situs web jahat tidak dapat membaca data yang diminta dari alamat IP lokal).

Namun, melalui DNS rebinding, penyerang dapat mengendalikan asal permintaan mereka untuk sementara sehingga permintaan tersebut tampak berasal dari alamat IP lokal. Hal ini dilakukan dengan mengendalikan situs web dan server DNS yang digunakan untuk menyelesaikan alamat IP-nya. Lihat wiki DNS Rebinding untuk detail selengkapnya.

Mitigasi

  • Nonaktifkan inspektur pada sinyal SIGUSR1 dengan melampirkan pendengar process.on(‘SIGUSR1’, …) padanya.
  • Jangan jalankan protokol inspektur dalam produksi.

 

Paparan Informasi Sensitif kepada Aktor yang Tidak Sah (CWE-552)

Semua file dan folder yang disertakan dalam direktori saat ini akan dipindahkan ke registri npm selama penerbitan paket.

Ada beberapa mekanisme untuk mengendalikan perilaku ini dengan menetapkan daftar blokir dengan .npmignore dan .gitignore atau dengan menetapkan daftar izin di package.json

Mitigasi

  • Gunakan npm publishing --dry-run untuk mencantumkan semua file yang akan dipublikasikan. Pastikan untuk meninjau konten sebelum menerbitkan paket.
  • Penting juga untuk membuat dan memelihara file yang diabaikan seperti .gitignore dan .npmignore. Di seluruh file ini, Anda dapat menentukan file/folder mana yang tidak boleh dipublikasikan. Properti file di package.json memungkinkan operasi kebalikan -- daftar yang diizinkan.
  • Jika terjadi paparan, pastikan untuk membatalkan penerbitan paket.

 

Penyelundupan Permintaan HTTP (CWE-444)

Ini adalah serangan yang melibatkan dua server HTTP (biasanya proxy dan aplikasi Node.js). Klien mengirimkan permintaan HTTP yang terlebih dahulu melewati server front-end (proxy) dan kemudian dialihkan ke server back-end (aplikasi). Ketika front-end dan back-end menafsirkan permintaan HTTP yang ambigu secara berbeda, ada potensi bagi penyerang untuk mengirim pesan jahat yang tidak akan terlihat oleh front-end tetapi akan terlihat oleh back-end, yang secara efektif "menyelundupkannya" melewati server proxy.

Lihat CWE-444 untuk deskripsi dan contoh yang lebih terperinci.

Karena serangan ini bergantung pada Node.js yang menafsirkan permintaan HTTP secara berbeda dari server HTTP (sewenang-wenang), serangan yang berhasil dapat disebabkan oleh kerentanan di Node.js, server front-end, atau keduanya. Jika cara permintaan ditafsirkan oleh Node.js konsisten dengan spesifikasi HTTP (lihat RFC7230), maka itu tidak dianggap sebagai kerentanan di Node.js.

Mitigasi

  • Jangan gunakan opsi insecureHTTPParser saat membuat Server HTTP.
  • Konfigurasikan server front-end untuk menormalkan permintaan yang ambigu.
  • Pantau terus kerentanan penyelundupan permintaan HTTP baru di Node.js dan server front-end pilihan.
  • Gunakan HTTP/2 secara menyeluruh dan nonaktifkan penurunan HTTP jika memungkinkan.

 

Pemaparan Informasi melalui Serangan Waktu (CWE-208)

Ini adalah serangan yang memungkinkan penyerang mempelajari informasi yang berpotensi sensitif dengan, misalnya, mengukur berapa lama waktu yang dibutuhkan aplikasi untuk menanggapi permintaan. Serangan ini tidak khusus untuk Node.js dan dapat menargetkan hampir semua runtime.

Serangan ini mungkin terjadi setiap kali aplikasi menggunakan rahasia dalam operasi yang sensitif terhadap waktu (misalnya, cabang). Pertimbangkan penanganan autentikasi dalam aplikasi umum. Di sini, metode autentikasi dasar mencakup email dan kata sandi sebagai kredensial. Informasi pengguna diambil dari input yang telah diberikan pengguna dari idealnya DBMS. Setelah mengambil informasi pengguna, kata sandi dibandingkan dengan informasi pengguna yang diambil dari basis data. Menggunakan perbandingan string bawaan membutuhkan waktu lebih lama untuk nilai dengan panjang yang sama. Perbandingan ini, ketika dijalankan untuk jumlah yang dapat diterima, secara tidak sengaja meningkatkan waktu respons permintaan. Dengan membandingkan waktu respons permintaan, penyerang dapat menebak panjang dan nilai kata sandi dalam sejumlah besar permintaan.

Mitigasi

  • API kripto mengekspos fungsi timingSafeEqual untuk membandingkan nilai sensitif aktual dan yang diharapkan menggunakan algoritme waktu-konstan.
  • Untuk perbandingan kata sandi, Anda dapat menggunakan skrip yang juga tersedia pada modul kripto asli.
  • Secara umum, hindari penggunaan rahasia dalam operasi waktu-variabel. Ini termasuk percabangan pada rahasia dan, ketika penyerang dapat berada di lokasi yang sama pada infrastruktur yang sama (misalnya, mesin cloud yang sama), menggunakan rahasia sebagai indeks ke dalam memori. Menulis kode waktu-konstan dalam JavaScript sulit (sebagian karena JIT). Untuk aplikasi kripto, gunakan API kripto bawaan atau WebAssembly (untuk algoritme yang tidak diimplementasikan secara asli).

 

Modul Pihak Ketiga yang Berbahaya (CWE-1357)

Saat ini, di Node.js, paket apa pun dapat mengakses sumber daya yang kuat seperti akses jaringan. Lebih jauh lagi, karena mereka juga memiliki akses ke sistem berkas, mereka dapat mengirim data apa pun ke mana pun.

Semua kode yang berjalan ke dalam proses node memiliki kemampuan untuk memuat dan menjalankan kode arbitrer tambahan dengan menggunakan eval() (atau yang setara). Semua kode dengan akses tulis sistem berkas dapat mencapai hal yang sama dengan menulis ke berkas baru atau yang sudah ada yang dimuat.

Node.js memiliki mekanisme kebijakan eksperimental¹ untuk mendeklarasikan sumber daya yang dimuat sebagai tidak tepercaya atau tepercaya. Namun, kebijakan ini tidak diaktifkan secara default. Pastikan untuk menyematkan versi dependensi dan menjalankan pemeriksaan otomatis untuk kerentanan menggunakan alur kerja umum atau skrip npm. Sebelum memasang paket, pastikan bahwa paket ini dipelihara dan menyertakan semua konten yang Anda harapkan. Hati-hati, kode sumber GitHub tidak selalu sama dengan yang dipublikasikan, validasi di node_modules. 

 

Serangan rantai pasokan

Serangan rantai pasokan pada aplikasi Node.js terjadi ketika salah satu dependensinya (baik langsung maupun transitif) terganggu. Hal ini dapat terjadi karena aplikasi terlalu longgar dalam menentukan dependensi (yang memungkinkan pembaruan yang tidak diinginkan) dan/atau kesalahan ketik umum dalam spesifikasi (rentan terhadap typosquatting).

Penyerang yang mengambil alih paket hulu dapat menerbitkan versi baru dengan kode berbahaya di dalamnya. Jika aplikasi Node.js bergantung pada paket tersebut tanpa ketat menentukan versi mana yang aman untuk digunakan, paket tersebut dapat secara otomatis diperbarui ke versi berbahaya terbaru, yang membahayakan aplikasi.

Dependensi yang ditentukan dalam file package.json dapat memiliki nomor versi yang tepat atau rentang. Namun, saat menyematkan dependensi ke versi yang tepat, dependensi transitifnya sendiri tidak disematkan. Hal ini tetap membuat aplikasi rentan terhadap pembaruan yang tidak diinginkan/tak terduga.

 

Kemungkinan vektor serangan:

  • Serangan typosquatting
  • Peracunan lockfile
  • Pengelola yang disusupi
  • Paket Berbahaya
  • Kebingungan Ketergantungan


Mitigasi

  • Cegah npm mengeksekusi skrip sembarangan dengan --ignore-scripts
  • Selain itu, Anda dapat menonaktifkannya secara global dengan npm config set ignore-scripts true
  • Sematkan versi ketergantungan ke versi tertentu yang tidak dapat diubah, bukan versi yang berupa rentang atau dari sumber yang dapat diubah.
  • Gunakan lockfile, yang menyematkan setiap ketergantungan (langsung dan transitif).
  • Gunakan Mitigasi untuk keracunan lockfile.
  • Otomatiskan pemeriksaan kerentanan baru menggunakan CI, dengan alat seperti npm-audit.
  • Alat seperti Socket dapat digunakan untuk menganalisis paket dengan analisis statis untuk menemukan perilaku berisiko seperti akses jaringan atau sistem berkas.
  • Gunakan npm ci alih-alih npm install. Ini memberlakukan lockfile sehingga ketidakkonsistenan antara file tersebut dan file package.json menyebabkan kesalahan (alih-alih mengabaikan lockfile secara diam-diam demi package.json). Periksa dengan cermat file package.json untuk melihat kesalahan/kesalahan ketik pada nama dependensi.

 

Pelanggaran Akses Memori (CWE-284)

Serangan berbasis memori atau berbasis heap bergantung pada kombinasi kesalahan manajemen memori dan pengalokasi memori yang dapat dieksploitasi. Seperti semua runtime, Node.js rentan terhadap serangan ini jika proyek Anda berjalan pada mesin bersama. Menggunakan heap aman berguna untuk mencegah kebocoran informasi sensitif karena pointer overrun dan underrun.

Sayangnya, heap aman tidak tersedia di Windows. Informasi selengkapnya dapat ditemukan pada dokumentasi heap aman Node.js.

Mitigasi

  • Gunakan --secure-heap=n tergantung pada aplikasi Anda, di mana n adalah ukuran byte maksimum yang dialokasikan.
  • Jangan jalankan aplikasi produksi Anda pada mesin bersama.


Monkey Patching (CWE-349)

Monkey patching mengacu pada modifikasi properti dalam runtime yang bertujuan untuk mengubah perilaku yang ada. Contoh:

 // eslint-disable-next-line no-extend-native
Array.prototype.push = function (item) {
  // overriding the global [].push
};

Mitigasi

  • Flag --frozen-intrinsics mengaktifkan intrinsik beku eksperimental¹, yang berarti semua objek dan fungsi JavaScript bawaan dibekukan secara rekursif. Oleh karena itu, cuplikan berikut tidak akan menggantikan perilaku default Array.prototype.push

 // eslint-disable-next-line no-extend-native
Array.prototype.push = function (item) {
  // overriding the global [].push
};

// Uncaught:
// TypeError <Object <Object <[Object: null prototype] {}>>>:
// Cannot assign to read only property 'push' of object ''

Namun, penting untuk disebutkan bahwa Anda masih dapat menentukan global baru dan mengganti global yang ada menggunakan globalThis

 > globalThis.foo = 3; foo; // you can still define new globals
3
> globalThis.Array = 4; Array; // However, you can also replace existing globals
4

Oleh karena itu, Object.freeze(globalThis) dapat digunakan untuk menjamin tidak ada global yang akan diganti.
 

Serangan Pencemaran Prototipe (CWE-1321)

Pencemaran prototipe mengacu pada kemungkinan memodifikasi atau menyuntikkan properti ke dalam item bahasa Javascript dengan menyalahgunakan penggunaan __proto_, _constructor, prototipe, dan properti lain yang diwarisi dari prototipe bawaan.

 const a = { a: 1, b: 2 };
const data = JSON.parse('{"__proto__": { "polluted": true}}');

const c = Object.assign({}, a, data);
console.log(c.polluted); // true

// Potential DoS
const data2 = JSON.parse('{"__proto__": null}');
const d = Object.assign(a, data2);
d.hasOwnProperty('b'); // Uncaught TypeError: d.hasOwnProperty is not a function

 Ini adalah potensi kerentanan yang diwarisi dari bahasa JavaScript.

Contoh:

 

Mitigasi

  • Hindari insecure recursive merges, lihat CVE-2018-16487..
  • Terapkan validasi Skema JSON untuk permintaan eksternal/tidak tepercaya.
  • Buat Objek tanpa prototipe dengan menggunakan Object.create(null).
  • Bekukan prototipe: Object.freeze(MyObject.prototype).
  • Nonaktifkan properti Object.prototype.__proto__ menggunakan tanda --disable-proto.
  • Periksa apakah properti tersebut ada langsung pada objek, bukan dari prototipe menggunakan Object.hasOwn(obj, keyFromObj).
  • Hindari penggunaan metode dari Object.prototype.

 

Node.js memuat modul mengikuti Algoritma Resolusi Modul. Oleh karena itu, ia menganggap direktori tempat modul diminta (require) tepercaya.

Dengan demikian, ini berarti perilaku aplikasi berikut diharapkan. Dengan menganggap struktur direktori berikut:

  • app/
    • server.js
    • auth.js
    • auth


Jika server.js menggunakan require('./auth'), ia akan mengikuti algoritma resolusi modul dan memuat auth alih-alih auth.js.

Mitigasi


Menggunakan mekanisme kebijakan eksperimental¹ dengan pemeriksaan integritas dapat menghindari ancaman di atas. Untuk direktori yang dijelaskan di atas, seseorang dapat menggunakan policy.json berikut

 {
  "resources": {
    "./app/auth.js": {
      "integrity": "sha256-iuGZ6SFVFpMuHUcJciQTIKpIyaQVigMZlvg9Lx66HV8="
    },
    "./app/server.js": {
      "dependencies": {
        "./auth": "./app/auth.js"
      },
      "integrity": "sha256-NPtLCQ0ntPPWgfVEgX46ryTNpdvTWdQPoZO3kHo0bKI="
    }
  }
}

 Oleh karena itu, ketika membutuhkan modul auth, sistem akan memvalidasi integritas dan menampilkan kesalahan jika tidak sesuai dengan yang diharapkan.

 Â» node --experimental-policy=policy.json app/server.js
node:internal/policy/sri:65
      throw new ERR_SRI_PARSE(str, str[prevIndex], prevIndex);
      ^

SyntaxError [ERR_SRI_PARSE]: Subresource Integrity string "sha256-iuGZ6SFVFpMuHUcJciQTIKpIyaQVigMZlvg9Lx66HV8=%" had an unexpected "%" at position 51
    at new NodeError (node:internal/errors:393:5)
    at Object.parse (node:internal/policy/sri:65:13)
    at processEntry (node:internal/policy/manifest:581:38)
    at Manifest.assertIntegrity (node:internal/policy/manifest:588:32)
    at Module._compile (node:internal/modules/cjs/loader:1119:21)
    at Module._extensions..js (node:internal/modules/cjs/loader:1213:10)
    at Module.load (node:internal/modules/cjs/loader:1037:32)
    at Module._load (node:internal/modules/cjs/loader:878:12)
    at Module.require (node:internal/modules/cjs/loader:1061:19)
    at require (node:internal/modules/cjs/helpers:99:18) {
  code: 'ERR_SRI_PARSE'
}

Catatan, selalu disarankan untuk menggunakan --policy-integrity guna menghindari mutasi kebijakan.
 

Fitur Eksperimental dalam Produksi

Penggunaan fitur eksperimental dalam produksi tidak disarankan. Fitur eksperimental dapat mengalami perubahan yang merusak jika diperlukan, dan fungsinya tidak stabil secara aman. Meskipun demikian, umpan balik sangat dihargai.
 

Alat OpenSSF

OpenSSF memimpin beberapa inisiatif yang dapat sangat berguna, terutama jika Anda berencana untuk menerbitkan paket npm. Inisiatif ini meliputi:

  • Kartu Skor OpenSSF Kartu Skor mengevaluasi proyek sumber terbuka menggunakan serangkaian pemeriksaan risiko keamanan otomatis. Anda dapat menggunakannya untuk menilai kerentanan dan dependensi secara proaktif dalam basis kode Anda dan membuat keputusan yang tepat tentang penerimaan kerentanan.
  • Program Lencana Praktik Terbaik OpenSSF Proyek dapat secara sukarela melakukan sertifikasi mandiri dengan menjelaskan bagaimana mereka mematuhi setiap praktik terbaik. Ini akan menghasilkan lencana yang dapat ditambahkan ke proyek.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Post a Comment

0 Comments