FlawOpen

flawopen.com/Command Injection/Java Runtime.exec()

Runtime.exec() protège-t-il de Command Injection ?

CWE-78: OS Command InjectionPage de référence
Réponse courte

Runtime.exec(String) ne lance pas implicitement de shell ; les opérateurs shell ne sont donc pas automatiquement interprétés. Mais la chaîne est découpée en programme et arguments, et une entrée non fiable peut modifier les arguments reçus par le programme. ProcessBuilder rend les limites explicites ; validez chaque valeur et contrôlez l’exécutable ainsi que les options admises.

RISQUÉ
// L’entrée utilisateur est concaténée à la chaîne de commande
Runtime.getRuntime().exec(
  "approved-tool --input " + filename
);
PLUS SÛR
// Exécutable fixe et arguments séparés ; validez filename d’abord
String safeName = validateFilename(filename);
new ProcessBuilder(
  "/opt/app/bin/approved-tool",
  "--input", safeName
).start();

Injection shell et injection d’arguments sont différentes

Depuis Java 18, Oracle déprécie Runtime.exec(String), jugé source d’erreurs, et recommande exec(String[]) ou ProcessBuilder. La surcharge avec une chaîne découpe les arguments aux espaces, ce qui peut fractionner un chemin qui en contient. Runtime.exec(String) ne lance pas implicitement sh ni un autre shell ; Oracle indique que cette surcharge convertit la chaîne en tableau d’arguments. Les métacaractères shell ordinaires ne deviennent donc pas une syntaxe shell, mais l’entrée reste risquée : la tokenisation peut créer des arguments supplémentaires et le programme peut interpréter un argument comme une option. ProcessBuilder reçoit une liste de chaînes représentant l’exécutable et ses arguments ; sur les plateformes courantes, chaque élément fixe une frontière. Gardez l’exécutable constant, validez les valeurs selon la grammaire attendue par le programme et refusez ou traitez les valeurs ressemblant à des options. N’utilisez -- que si la documentation du programme garantit ce comportement. Ne lancez pas explicitement un shell, par exemple sh -c, avec des données non fiables.

Questions fréquentes

L’absence de shell rend-elle Runtime.exec(String) sûre ?

Non. Elle réduit le risque d’injection shell pour cette surcharge, mais l’injection d’arguments reste possible. Le programme peut interpréter une entrée contrôlée comme une option ou un nom de fichier. Utilisez ProcessBuilder avec un exécutable fixe et des arguments séparés, puis validez chaque valeur selon le programme.

ProcessBuilder valide-t-il les arguments à ma place ?

Non. Il construit la liste du programme et des arguments puis démarre le processus ; il ne vérifie pas leur sûreté ni leur validité. Appliquez des listes blanches et une validation côté application, conformément aux règles d’arguments du programme.

Références

À voir aussi Injection de commandes système (CWE-78) : fonctionnement et prévention dans tous les langages — flawopen.com Risque de command injection avec Node.js exec() Node.js exec() vs execFile() : différences et sécurité