FlawOpen

flawopen.com/Command Injection/Node child_process.exec

Risiko command injection pada Node.js child_process.exec()

Halaman referensi
Penjelasan sederhana

Memberikan string perintah ke exec() seperti menyerahkan kalimat kepada penata huruf dan membiarkan tanda baca menentukan batas instruksi. Jika teks tak tepercaya berisi sintaks shell, shell dapat membacanya sebagai instruksi kontrol. execFile() mengirim program tetap dan argumen terpisah tanpa parsing shell secara default.

RENTAN
const { exec } = require('node:child_process');

function inspectFile(filename) {
  return exec(`file ${filename}`);
}
DIPERBAIKI
const { execFile } = require('node:child_process');

const allowed = new Map([
  ['report-1', '/srv/reports/1.pdf'],
  ['report-2', '/srv/reports/2.pdf']
]);

function inspectReport(reportId) {
  const path = allowed.get(reportId);
  if (!path) throw new Error('Unknown report');
  return execFile('/usr/bin/file', ['--', path], {
    shell: false,
    timeout: 3000,
    maxBuffer: 64 * 1024
  });
}

Mengapa execFile() mengurangi risiko command injection

exec() memulai shell dan memberikan string perintah kepadanya. Jika kode menyisipkan teks yang dikendalikan penyerang, shell memproses metakarakter sebagai sintaks: inilah jalur command injection yang dijelaskan CWE-78. execFile() menjalankan executable tertentu dengan array argumen dan secara default tidak membuat shell, sehingga pemisah shell tidak diproses ulang oleh shell. Contoh ini juga memetakan ID pemanggil ke path tetap. Ini tidak membuat semua program target aman: validasi argumen yang diterima program, gunakan terminator opsi seperti -- jika didukung, dan jangan aktifkan shell: true untuk nilai tak tepercaya.

Cara menemukan pemanggilan exec() yang berisiko

Cari exec() dan execSync(), lalu telusuri setiap string perintah ke parameter request, kolom database, nama file, dan variabel lingkungan. Catat executable dan batas tiap argumen. Utamakan API langsung; jika tidak memungkinkan, gunakan execFile() dengan executable tetap, argumen tervalidasi, batas waktu, dan batas keluaran.

grep -RInE 'exec(Sync)?[[:space:]]*\(' --include='*.js' --include='*.cjs' --include='*.mjs' --include='*.ts' .

Varian sinkron

Bagaimana dengan execSync()?

execSync() memakai string perintah berbasis shell yang sama sehingga risikonya sama, sekaligus memblokir event loop. execFileSync() secara default menghindari parsing shell, tetapi executable dan argumennya tetap harus divalidasi.

Referensi

Lihat juga Injeksi perintah OS (CWE-78): cara kerja dan cara mencegahnya di setiap bahasa — flawopen.com Node.js exec() vs execFile(): perbedaan dan keamanan Java Runtime.exec() dan Command Injection: apa bedanya?