如何在节点中为shell命令转义字符串?

时间:2009-11-22 20:21:53

标签: javascript shell escaping node.js v8

nodejs中,执行外部命令的唯一方法是通过sys.exec(cmd)。我想调用外部命令并通过stdin给它数据。在nodejs中,似乎还没有一种方法可以打开命令然后将数据推送到它(只是执行并接收其标准+错误输出),所以看来我现在必须这样做的唯一方法是通过单个字符串命令,如:

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

像这样的问题的大多数答案都集中在nodegs(使用Google的V8 Javascript引擎)中的正则表达式或者其他语言(如Python)的本机功能。

我想逃避dangerStr,以便像上面那样组成一个exec字符串是安全的。如果有帮助,dangerStr将包含JSON数据。

7 个答案:

答案 0 :(得分:36)

这就是我使用的:

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

答案 1 :(得分:13)

如果您需要简单的解决方案,可以使用:

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

因此,克里斯·约翰森提到,你的字符串只会被单引号转义。

echo 'John'\''s phone';

由于strong quoting,它适用于bash,感觉它在fish中也有效,但在zshsh中无效。

如果您有bash,则可以shzsh '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('; ')]);

度过美好的一天!

答案 2 :(得分:6)

should never rely on escaping unknown input going to a shell parameter - 几乎总会有一些你想到的边缘情况允许用户在你的服务器上执行任意代码。

Node支持调用命令并单独传递每个参数,不需要转义。这是最安全的方法:

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

答案 3 :(得分:3)

我赞同Will的意见,只要有可能,就应避免手工逃脱,而应避免产生卵子。

但是,在无法避免转义的情况下,例如,如果您需要使用exec或您是executing a command through ssh。然后,您可以使用base64将安全字符传递给bash,并依靠bash逃逸未知字符。

let positions;
$("body").on('click', '.check_box', function() {
  positions = [];
  $(".check_box:checked").each(function() {
    positions.push([
     $(this).data('id'), $(this).data('status')
   ]);
  });
  console.log(positions);
});

解释如下:

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <input type="checkbox" class="check_box" data-id="8" data-status="0"> <input type="checkbox" class="check_box" data-id="10" data-status="0">是未知的,但在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中传递的实际值,这是安全的,并且具有与用户想要的值相同的值。

答案 4 :(得分:0)

有一种方法可以写入外部命令:process.createChildProcessdocumentation)返回一个带有write方法的对象。 createChildProcess虽然不方便,因为它不会缓冲stdout和stderr,所以你需要事件处理程序来读取块中的输出。

var stdout = "", stderr = "";
var child = process.createChildProcess("someCommand");

child.addListener("output", function (data) {
    if (data !== null) {
        stdout += data;
    }
});
child.addListener("error", function (data) {
    if (data !== null) {
        stderr += data;
    }
});
child.addListener("exit", function (code) {
    if (code === 0) {
        sys.puts(stdout);
    }
    else {
        // error
    }
});

child.write("This goes to someCommand's stdin.");

答案 5 :(得分:0)

如果您正在构建自己的软件,您可以将命令编码为 base64 或十六进制格式,然后从程序中解码参数。

对于我使用的 Nodejs 应用程序。

var base64_encode = exports.base64_encode = function(non_base64_string){
    return Buffer.from(non_base64_string).toString('base64');
}


var base64_decode = exports.base64_decode = function(base64_string){
    return Buffer.from(base64_string, 'base64').toString('ascii')
}

所以当我像这样运行 base64 编码的命令时

webman grep --search "aW5jbHVkZV9vbmNlICRfU0VSVkVSWyJET0NVTUVOVF9ST09UIl0uIi9zZXR0aW5ncy5waHAiOw==" --replacement "JGRvY3VtZW50X3Jvb3QgPSBfX0RJUl9fO3doaWxlKHRydWUpe2lmIChmaWxlX2V4aXN0cygkZG9jdW1lbnRfcm9vdC4iL3NldHRpbmdzLmpzb24iKSl7YnJlYWs7fWVsc2V7JGRvY3VtZW50X3Jvb3Q9ZGlybmFtZSgkZG9jdW1lbnRfcm9vdCk7fX08bmV3bGluZT5pbmNsdWRlX29uY2UgJGRvY3VtZW50X3Jvb3QuIi9zZXR0aW5ncy5waHAiOw=="

我可以使用 search

毫无压力地获取参数 replacementbase64_decode 参数

答案 6 :(得分:-2)

如果你还需要处理特殊字符(换行符等),你可以这样做:

str = JSON.stringify(str)
    .replace(/^"|"$/g,'') //remove JSON-string double quotes
    .replace(/'/g, '\'"\'"\'') //escape single quotes the ugly bash way

这假设您通过单引号使用Bash的strong-quoting,并且接收方可以理解JSON的C类转义。