web-dev-qa-db-fra.com

Comment échapper une chaîne pour une commande Shell dans un nœud?

Dans nodejs , la seule façon d'exécuter des commandes externes est via sys.exec (cmd). Je voudrais appeler une commande externe et lui donner des données via stdin. Dans nodejs, il ne semble pas encore y avoir de moyen d'ouvrir une commande, puis de lui envoyer des données (uniquement pour exécuter et recevoir ses sorties standard + erreur), il semble donc que la seule façon dont je dois le faire maintenant est via une commande à chaîne unique telle que:

var dangerStr = "bad stuff here";
sys.exec("echo '" + dangerStr + "' | somecommand");

La plupart des réponses à des questions comme celle-ci se sont concentrées sur les expressions rationnelles qui ne fonctionnent pas pour moi dans nodejs (qui utilise le moteur Javascript V8 de Google) ou sur les fonctionnalités natives d'autres langues comme Python.

Je voudrais échapper à dangerStr pour pouvoir composer en toute sécurité une chaîne exécutée comme celle ci-dessus. Si cela aide, dangerStr contiendra des données JSON.

43
Maciek

Voici ce que j'utilise:

var escapeShell = function(cmd) {
  return '"'+cmd.replace(/(["\s'$`\\])/g,'\\$1')+'"';
};
36
Sylvain Zimmer

Si vous avez besoin d'une solution simple, vous pouvez l'utiliser:

function escapeShellArg (arg) {
    return `'${arg.replace(/'/g, `'\\''`)}'`;
}

Ainsi, votre chaîne sera simplement échappée avec des guillemets simples comme l'a mentionné Chris Johnsen.

echo 'John'\''s phone';

Cela fonctionne dans bash à cause de guillemets forts , on dirait qu'il fonctionne également dans fish, mais ne fonctionne pas dans zsh et sh.

Si vous avez bash, vous pouvez exécuter votre script dans sh ou zsh avec 'bash -c \'' + escape('all-the-rest-escaped') + '\''.

Mais en fait ... node.js échappera à vous tous les caractères nécessaires:

var child = require('child_process')
  .spawn('echo', ['`echo 1`;"echo $SSH_TTY;\'\\0{0..5}']);

child.stdout.on('data', function (data) {
  console.log('stdout: ' + data);
});

child.stderr.on('data', function (data) {
  console.log('stderr: ' + data);
});

ce bloc de code s'exécutera:

echo '`echo 1`;"echo $SSH_TTY;'\''\\0{0..5}'

et affichera:

stdout: `echo 1`;"echo $SSH_TTY;\'\\0{0..5}

ou une erreur.

Jetez un œil à http://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options

À propos, une solution simple pour exécuter un tas de commandes est la suivante:

require('child_process')
  .spawn('sh', ['-c', [
    'cd all/your/commands',
    'ls here',
    'echo "and even" > more'
  ].join('; ')]);

Bonne journée!

21
Alex Yaroshevich

Vous ne devez jamais compter sur l'échappement d'une entrée inconnue pour accéder à un paramètre Shell - il y aura presque toujours des cas Edge n'y ai pas pensé qui permet à l'utilisateur d'exécuter du code arbitraire sur votre serveur.

Node prend en charge l'appel d'une commande et la transmission de chaque argument séparément, sans échappement requis. C'est le moyen le plus sûr de le faire:

const { spawn } = require('child_process');
// Note that the arguments are in an array, not using string interpolation
const ls = spawn('ls', ['-lh', '/usr']);

ls.stdout.on('data', (data) => {
  console.log(`stdout: ${data}`);
});

ls.stderr.on('data', (data) => {
  console.log(`stderr: ${data}`);
});

ls.on('close', (code) => {
  console.log(`child process exited with code ${code}`);
});

La documentation est ici

10
Will Richardson

J'appuie l'opinion de Will , dans la mesure du possible, vous devriez éviter de vous échapper à la main et préférer le frai.

Cependant, dans le cas où l'échappement est inévitable, par exemple si vous devez utiliser exec ou si vous êtes exécutant une commande via ssh . Ensuite, vous pouvez utiliser base64 pour passer des caractères sûrs à bash et compter sur bash pour échapper à l'inconnu.

const dangerStr = 'bad stuff here'
// base64 has safe characters [A-Za-z=0-9+/]
const dangerBase64 = btoa(dangerStr)

sys.exec(`echo "$(echo ${dangerBase64} | base64 -d)" | somecommand`)

L'explication est la suivante:

dangerBase64 Est inconnu mais il ne contient pas de caractères dangereux dans bash . Par conséquent, echo ${dangerBase64} Affichera ce que nous voulons.

Enfin, le double guillemet autour de $(echo ${dangerBase64} | base64 -d) échappe à la valeur réelle transmise par l'utilisateur dans bash, qui est sûre et a la même valeur que l'utilisateur voulait.

0
Gabriel Furstenheim