web-dev-qa-db-ja.com

ノードでシェルコマンドの文字列をエスケープするにはどうすればよいですか?

nodejs では、外部コマンドを実行する唯一の方法はsys.exec(cmd)を使用することです。外部コマンドを呼び出して、stdin経由でデータを渡したいのですが。 nodejsにはまだコマンドを開いてデータをプッシュする方法がないようです(実行して標準+エラー出力を受け取るためだけ)ので、これが今これを行う唯一の方法です次のような単一の文字列コマンドを使用:

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

このような質問に対するほとんどの回答は、nodejs(GoogleのV8 JavaScriptエンジンを使用)では機能しない正規表現、またはPythonなどの他の言語のネイティブ機能に焦点を当てています。

上記のようなexec文字列を安全に作成できるように、dangerStrをエスケープしたいのですが。役立つ場合、dangerStrにはJSONデータが含まれます。

43
Maciek

これは私が使用するものです:

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

単純なソリューションが必要な場合は、これを使用できます。

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

したがって、Chris Johnsenが言及したように、文字列は単一引用符でエスケープされます。

_echo 'John'\''s phone';
_

強い引用 のため、bashで機能しますが、fishでも機能するように感じますが、zshおよびsh

bashがある場合は、shまたはzsh'bash -c \'' + escape('all-the-rest-escaped') + '\''を使用してスクリプトを実行できます。

しかし、実際には... node.jsは必要なすべての文字をエスケープします。

_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);
});
_

このコードブロックは実行されます。

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

そして出力します:

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

またはいくつかのエラー。

http://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options を見てください。

ちなみに、一連のコマンドを実行する簡単なソリューションは次のとおりです。

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

ごきげんよう!

21

あなたは shouldnever頼りにして未知の入力をエスケープしてシェルパラメータに行く -ほとんどの場合、エッジケースがいくつかありますユーザーがサーバー上で任意のコードを実行することを許可することは考えていません。

ノードはコマンドを呼び出し、各引数を個別に渡すことができるため、エスケープは不要です。これが最も安全な方法です。

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}`);
});

ドキュメントは here です

10
Will Richardson

私は Will の意見を2番目に述べます。可能な限り、手動での脱出を避け、スポーンを優先する必要があります。

ただし、エスケープが避けられない場合、たとえばexecを使用する必要がある場合、または sshを介してコマンドを実行する である場合。次に、base64を使用して安全な文字をbashに渡し、bashを使用して未知のものを回避できます。

_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`)
_

説明は次のとおりです。

_dangerBase64_は不明ですが、 bash に安全でない文字が含まれていません。したがって、_echo ${dangerBase64}_は必要なものを出力します。

最後に、$(echo ${dangerBase64} | base64 -d)を囲む二重引用符は、bash内でユーザーによって渡された実際の値をエスケープします。これは安全で、ユーザーが希望したのと同じ値を持っています。

0