Eval для имен файлов, зло?

У меня есть следующий скрипт для создания проектов:

clear version="0.0.2" echo "Project creator" echo "---------------" # ask user to specify a directory (could start with spelled-out home directory) directoryName="" # Input must meet the following criteria: # 1.) No spaces at all in the directory path # 2.) some characters must be entered while [[ ${#directoryName} -eq 0 || $directoryName == *" "* ]] do echo -e "\nEnter the full directory of the project (no spaces):" read directoryName done echo "You entered: $directoryName" # uate directoryName so that the rest of the code can understand it # create directory if it does not exist eval mkdir "$directoryName" # if successful if [ $? -eq 0 ] then # call executable in /home/miwarren/CPPFileCreator to create a main.cpp file to put in the folder $HOME/CPPFileCreator/a.out $directoryName # copy a run.sh file into the folder, too... eval cp $HOME/CPPFileCreator/run.sh $directoryName/run.sh # you might want to put a fileCreator.sh in the folder as well eval cp $HOME/fileCreator.sh $directoryName/fileCreator.sh fi 

Я обязательно вычеркиваю любые пробелы (предполагается, что каждая небезопасная строка имеет по крайней мере пробел в ней, потому что атака в стиле инъекций). Я хочу, чтобы пользователям не приходилось указывать пути, когда существуют переменные (например, $HOME для домашнего каталога).

Я все еще хорош, чтобы использовать здесь eval , а если нет, что делать?

2 Solutions collect form web for “Eval для имен файлов, зло?”

«Я хочу, чтобы пользователям не приходилось указывать пути, когда существуют переменные (например, $ HOME для домашнего каталога)».

Это можно сделать без eval :

 $ s='$HOME/.config' $ s="${s//\$HOME/$HOME}" $ echo "$s" /home/john1024/.config 

Это имеет некоторые ограничения. Во-первых, если оба HOMES и HOME являются именами переменных, которые вы хотите заменить, то, чтобы избежать ложных совпадений, HOMES необходимо заменить перед HOME.

Применение подстановок для всех экспортируемых переменных

Использование bash:

 while IFS== read -r name val do s="${s//\$$name/$val}" done < <(printenv) 

Например:

 $ export A=alpha; export B=beta $ s='$HOME/$A/$B' $ while IFS== read -r name val; do s="${s//\$$name/$val}"; done < <(printenv) $ echo "$s" /home/john1024/alpha/beta 

Поскольку этот подход не сортирует имена переменных по длине, он имеет проблему перекрытия переменных, упомянутую выше.

Мы можем исправить это, отсортировав имена переменных в соответствии с длиной:

 while IFS== read -rn name val do s="${s//\$$name/$val}" done < <(printenv | awk '/^[^ \t]/{key=$0; sub(/=.*/,"",key); printf "%s=%s\n",length(key),$0}' | sort -rnt=) 

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

 while IFS== read -rn name val do s="${s//\$\{$name\}/$val}" done < <(printenv | awk '/^[^ \t]/{key=$0; sub(/=.*/,"",key); printf "%s=%s\n",length(key),$0}' | sort -rnt=) 

В качестве примера:

 $ s='${HOME}/${A}/${B}' $ while IFS== read -rn name val; do s="${s//\$\{$name\}/$val}"; done < <(printenv | awk '/^[^ \t]/{key=$0; sub(/=.*/,"",key); printf "%s=%s\n",length(key),$0}' | sort -rnt=) $ echo "$s" /home/john1024/alpha/beta 

Использование eval здесь не имеет никакого смысла. Прежде чем вы решите, как исправить свой сценарий, тщательно подумайте о своих требованиях и запишите их . Читая свой вопрос, ясно, что у вас нет четкого понимания того, что вы хотите сделать, и вы не решите эту проблему, пока не выясните, чего вы ожидаете от решения.

предположил, что каждая небезопасная строка имеет по крайней мере пробел в ней

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

 `touch /tmp/this_is_executed`somefile $(touch /tmp/this_is_executed)somefile 

Это проблема? Это зависит от того, что вы пытаетесь сделать. Является ли вход от пользователя, который запускает ваш скрипт из обычной учетной записи? Если это так, проблема безопасности не возникает, но скрипт не имеет смысла читать входные данные со стандартного ввода: вместо этого он должен принимать аргумент командной строки, а затем оболочка командной строки будет делать нужные расширения переменных. Если ваш сценарий работает с повышенными привилегиями или принимает входные данные по сети, тогда eval является наиболее определенно злым, и вы не должны использовать его, пока не поймете последствия. eval принимает строку в качестве аргумента (если она содержит несколько аргументов, они объединяются вместе с пробелами между ними) и выполняет ее как код оболочки. Если вы не хотите выполнять код оболочки, eval – неправильный инструмент.

Если сценарий принимает непривилегированный ввод, то это неправильное место для выполнения расширения переменной. Сделайте это в интерфейсе, который передает входные данные вашему сценарию, работая с привилегиями пользователя (например, используйте Javascript, если вход поступает из веб-браузера). В вашем скрипте вам нужно будет проверить, что указанные имена файлов находятся в каталоге, к которому должен иметь доступ пользователь. Будьте осторожны .. и символические ссылки, которые могут позволить экранировать дерево каталогов, и о ведущем - которые могут быть проанализированы как опции вместо имен файлов .

  • Трубопровод из находки в grep
  • Как использовать аргументы, такие как $ 1 $ 2 ... в цикле for?
  • BASH: как передать аргумент по умолчанию, если никакие аргументы после первого не прошли
  • Восстановить от faking / proc / meminfo
  • Как создать цикл for с переменным числом итераций?
  • отображать переменную unix с помощью dbms_output.put_line
  • Производительность скрипта Bash
  • в чем смысл 1 в конце awk-скрипта
  • Объединять записи в зависимости от общих столбцов и указывать значения, которые являются необычными в последнем столбце как разделенные запятыми
  • Перейти на один уровень от несуществующего пути
  • Преобразование строки ввода в дату в сценарии оболочки
  • Linux и Unix - лучшая ОС в мире.