flawopen.com/Command Injection/exec() vs. execFile()
exec() vs. execFile() in Node.js: Wo liegt der Unterschied?
exec() erhält einen String und führt ihn in einer Shell aus: Pipes und Platzhalter funktionieren, aber Metazeichen in nicht vertrauenswürdigen Eingaben können auch den Befehl verändern. execFile() startet das angegebene Programm direkt mit einem Argumentarray und standardmäßig ohne Shell. Das verhindert Shell-Parsing, aber nicht jedes Risiko: Das Zielprogramm kann ein Argument weiterhin als Option interpretieren oder auf einen unerwarteten Wert reagieren.
Vergleich
exec(`ls ${dir} | grep .txt`,
(err, out) => {...})
// die Pipe funktioniert, aber auch Shell-Metazeichen.
execFile('ls', [dir],
(err, out) => {...})
// ohne Shell; prüfen Sie, wie ls das Argument dir interpretiert.
// break out of its own argument
Wann Sie Shell-Funktionen tatsächlich benötigen
Wenn ein Befehl Pipes, Platzhaltererweiterung oder Umleitungen benötigt, kann execFile() diese Funktionen nicht direkt abbilden. Bauen Sie die Pipeline vorzugsweise in Node.js auf, indem Sie jede Stufe separat starten und die Streams verbinden. Wenn exec() unvermeidbar ist, dürfen nicht vertrauenswürdige Eingaben nicht in den Befehlsstring gelangen. Shell-freie Argumentarrays verhindern außerdem keine Argument-Injection: Validieren Sie jeden Wert passend zum Zielprogramm, verwenden Sie --, wenn das Programm es unterstützt, und erlauben Sie nur vorgesehene Befehle und Optionen. Die Option shell: true aktiviert eine Shell bei APIs, die standardmäßig keine starten; übergeben Sie dabei niemals ungeprüfte Eingaben.
Häufige Fragen
Windows-Batchdateien verändern die Sicherheitsgrenze
Unter Windows lassen sich .bat- und .cmd-Dateien nicht direkt mit execFile() starten. Node dokumentiert den Aufruf über exec(), cmd.exe oder spawn() mit aktiviertem Shell-Modus; dabei wird die Interpretation durch einen Kommandointerpreter wieder eingeführt. Bevorzugen Sie ein natives ausführbares Programm oder eine direkte API. Wenn ein Batch-Aufruf unvermeidbar ist, halten Sie Skriptpfad und Argumente fest oder validieren Sie sie anhand des genauen Skriptvertrags. Node stuft außerdem ein Argumentarray mit shell: true als veraltet ein (seit v22.15.0 und v23.11.0).
spawn() arbeitet standardmäßig ebenfalls ohne Shell und akzeptiert ein Argumentarray. Der wichtigste praktische Unterschied ist die Ausgabe: spawn() liefert Streams, während execFile() die Ausgabe puffert. Keine der beiden Funktionen verhindert, dass das Programm ein Argument als Option interpretiert; validieren Sie es für das jeweilige Programm. shell: true aktiviert wieder das Shell-Parsing.