flawopen.com/Command Injection/exec() vs execFile()
exec() ou execFile() dans Node.js : quelle différence ?
exec() reçoit une chaîne et l’exécute dans un shell : les pipes et jokers fonctionnent, mais les métacaractères d’une entrée non fiable peuvent aussi modifier la commande. execFile() lance directement le programme indiqué avec un tableau d’arguments et sans shell par défaut. Cela évite l’analyse par le shell, mais pas tous les risques : le programme cible peut interpréter un argument comme une option ou agir sur une valeur inattendue.
Comparaison
exec(`ls ${dir} | grep .txt`,
(err, out) => {...})
// le pipe fonctionne, mais les métacaractères aussi.
execFile('ls', [dir],
(err, out) => {...})
// sans shell ; validez comment ls interprète l’argument dir.
// break out of its own argument
Quand vous avez réellement besoin des fonctions du shell
Si une commande exige des pipes, une expansion de jokers ou une redirection, execFile() ne propose pas directement ces fonctions. Préférez composer le pipeline dans Node.js en lançant chaque étape séparément et en reliant les streams. Si exec() est inévitable, gardez les entrées non fiables hors de la chaîne de commande. Un tableau d’arguments sans shell n’empêche pas non plus l’injection d’arguments : validez chaque valeur selon le programme cible, utilisez -- si ce programme le prend en charge et n’autorisez que les commandes et options prévues. L’option shell: true active un shell pour les API qui n’en lancent normalement pas ; dans ce mode, ne transmettez jamais d’entrée non assainie.
Questions fréquentes
Les fichiers batch Windows changent la frontière de sécurité
Sous Windows, les fichiers .bat et .cmd ne peuvent pas être lancés directement avec execFile(). Node documente leur invocation via exec(), cmd.exe ou spawn() avec un shell activé ; ces chemins réintroduisent l’analyse par l’interpréteur de commandes. Préférez un exécutable natif ou une API directe. Si l’appel d’un fichier batch est inévitable, gardez le chemin du script et ses arguments fixes, ou validez-les selon le contrat exact du script. Node déprécie également le passage d’un tableau d’arguments avec shell: true (depuis v22.15.0 et v23.11.0).
spawn() fonctionne également sans shell par défaut et accepte un tableau d’arguments. La principale différence pratique concerne la sortie : spawn() transmet des streams, tandis que execFile() met la sortie en mémoire tampon. Aucun des deux n’empêche le programme d’interpréter un argument comme une option ; validez-le pour ce programme. Définir shell: true réactive l’analyse par le shell.