FlawOpen

flawopen.com/Command Injection/Node child_process.exec

Command-Injection-Risiko bei Node.js child_process.exec()

Referenzseite
Einfach erklärt

Eine Befehlszeichenfolge an exec() zu übergeben ist, als gäbe man einem Setzer einen Satz und ließe ihn anhand der Satzzeichen entscheiden, wo Anweisungen enden. Enthält nicht vertrauenswürdiger Text Shell-Syntax, kann die Shell sie als Steueranweisung lesen. execFile() übergibt ein festes Programm und getrennte Argumente; standardmäßig wird keine Shell geparst.

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

function inspectFile(filename) {
  return exec(`file ${filename}`);
}
BEHOBEN
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
  });
}

Warum execFile() das Command-Injection-Risiko senkt

exec() startet eine Shell und übergibt ihr eine Befehlszeichenfolge. Interpoliert der Code darin angreiferkontrollierten Text, interpretiert die Shell Metazeichen als Syntax: Das ist der in CWE-78 beschriebene Command-Injection-Pfad. execFile() startet eine bestimmte ausführbare Datei mit einem Argumentarray und erzeugt standardmäßig keine Shell; Shell-Trennzeichen werden daher nicht erneut von einer Shell ausgewertet. Das Beispiel ordnet außerdem eine übergebene ID einem festen Pfad zu. Dadurch ist nicht jedes Zielprogramm sicher: Validiere dessen Argumente, verwende einen Optionsterminator wie --, sofern unterstützt, und aktiviere für nicht vertrauenswürdige Werte niemals shell: true.

Unsichere exec()-Aufrufe finden

Suche nach exec() und execSync() und verfolge jede Befehlszeichenfolge bis zu Request-Parametern, Datenbankfeldern, Dateinamen und Umgebungsvariablen. Halte die ausführbare Datei und die Argumentgrenzen fest. Bevorzuge eine direkte API; andernfalls nutze execFile() mit fester ausführbarer Datei, validierten Argumenten, Zeitlimit und begrenzter Ausgabe.

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

Synchrone Varianten

Was ist mit execSync()?

execSync() nutzt dieselbe shellbasierte Befehlszeichenfolge und hat dasselbe Injektionsrisiko; zusätzlich blockiert es die Event Loop. execFileSync() vermeidet standardmäßig die Shell-Auswertung, aber ausführbare Datei und Argumente müssen weiterhin validiert werden.

Referenzen

Siehe auch Befehlsinjektion ins Betriebssystem (CWE-78): Funktionsweise und Schutz in jeder Sprache — flawopen.com Node.js exec() vs. execFile(): Unterschiede und Sicherheit Java Runtime.exec() und Command Injection: Was ändert sich?