Экранирование данных при запуске команд из Node.js
Иногда приложение на Node.js должно запускать консольные команды для запуска других приложениях.
Например, представим, что нам нужно склонировать репозиторий с github. В обычном случае это делается достаточно просто:
import { exec } from 'child_process'
exec('git clone https://github.com/greensk/jquery.typograph myprojects/new'), (error, stdout, stderr) => {
if (error) {
console.log(error)
} else {
console.log('Успех!')
}
})Но всё становится чуть сложнее, если какой-то из параметров (например, адрес репозитория) должен вводить пользователь.
Казалось бы можно просто написать:
`git clone ${userTypedUrl} myprojects/new`Но так делать нельзя! Ведь злонамеренный пользователь может поставить в адрес репозитория пробел и добавить какие-то параметры к команде git clone. А таким образом можно сделать всё, что угодно. Например, склонировать проект не в myprojects, а в корень вашего веб-сервера!
Проблема экранирования
Если мы вставляем пользовательские данные в консольную команду, то очень важно провести экранирование специальных символов. Например, если пользователь по каким-то причинам ввёл пробел, то он должен быть экранирован при помощи символа \. В этом случае пробел будет восприниматься как часть адреса репозитория, а не как разделитель аргументов команды git clone.
Помимо пробела есть ещё много других специальных символов, которые могут как-то повлиять на интерпретацию команд, и которые нужно заэкранировать. Сделать это самостоятельно достаточно сложно, потому что есть много нюансов.
Используем shell-escape
Лучше всего использовать готовую библиотеку. В Node.js для этого есть библиотека shell-espace
npm install --save shell-escapeПосле этого код следует преобразовать таким образом:
import { exec } from 'child_process'
import shellescape from 'shell-escape'
exec(shellescape(['git', 'clone', userTypedUrl, 'myprojects/new']), (error, stdout, stderr) => {
if (error) {
console.log(error)
} else {
console.log('Успех!')
}
})