Как мне экранировать строку для команды оболочки в узле?

StackOverflow https://stackoverflow.com/questions/1779858

Вопрос

В nodejs, единственный способ выполнить внешние команды — через sys.exec(cmd).Я хотел бы вызвать внешнюю команду и передать ей данные через стандартный ввод.В nodejs, похоже, еще нет способа открыть команду, а затем передать в нее данные (только для выполнения и получения ее стандартных результатов + ошибок), поэтому, похоже, единственный способ сделать это прямо сейчас - с помощью одной строковой команды, например:

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

Большинство ответов на подобные вопросы касались либо регулярных выражений, которые у меня не работают в nodejs (который использует движок Google V8 Javascript), либо собственных функций других языков, таких как Python.

Я хотел бы избежать опасностиStr, чтобы можно было безопасно составить строку exec, подобную приведенной выше.Если это поможет, опасностьStr будет содержать данные JSON.

Это было полезно?

Решение

Существует способ записи во внешнюю команду: process.createChildProcess (документация) возвращает объект с 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.");

Другие советы

Это то, что я использую:

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

Если вам нужно простое решение, вы можете использовать это:

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

Таким образом, ваша строка будет просто экранирована одинарными кавычками, как упомянул Крис Джонсен.

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('; ')]);

Хорошего дня!

Ты должен никогда полагаться на экранирование неизвестного ввода, передаваемого в параметр оболочки - почти всегда будет какой-то крайний случай, о котором вы не подумали, который позволяет пользователю выполнять произвольный код на вашем сервере.

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

Документация здесь

Если вам также нужно иметь дело со специальными символами (переносами строк и т. д.), вы можете сделать это следующим образом:

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

Предполагается, что вы используете Bash сильное цитирование через одинарные кавычки), и получатель сможет понять C-подобное экранирование JSON.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top