John cannot use "--incremental:all" - No charset defined for mode: all

Вопросы

Когда целесообразно использовать?

Когда аргументы eval правильно заключены в кавычки (два уровня) и значения переменных, расширенные eval при первом синтаксическом анализе, не станут исполняемыми командами при втором синтаксическом анализе .

Почему использование eval - плохая идея?

Это не IMO (и этот вопрос требует мнений), если вы действительно знаете, что делаете.

Во-первых: проверьте, что (eval) того, что вы написали, соответствует вашим ожиданиям, заменив eval на echo и Во-вторых: хорошенько подумайте, какие переменные устанавливаются локально и какие значения они могут иметь.

Существуют ли какие-либо правила, согласно которым его можно использовать с полной и полной безопасностью, или это всегда и неизбежно дыра в безопасности?

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

Но это всегда риск (например, риск написания неверного сценария).
Так получилось, что eval увеличивает риск до некоторой степени.

Это обязательно потребует подробного описания:

Подробности:

Команда eval (всегда встроенная) позволяет дважды проанализировать командную строку.

В принципе, она не более или менее опасна, чем любая другая команда (вспомните rm -rf / ). Он будет выполнен с текущими правами пользователя, поэтому дважды подумайте, прежде чем использовать его с правами root. Но это также верно для команды rm , показанной выше. Для ограниченного пользователя rm завершится ошибкой в ​​большинстве каталогов, принадлежащих пользователю root. Но rm по-прежнему опасная команда.

Известная идиома.

Команда eval очень полезна (и совершенно безопасна) в известных идиомах.
Например, это выражение выводит значение последнего позиционного параметра :

$ set -- "ls -l" "*" "c;date"

$ eval echo \"\$\{$#\}\"          ### command under test

c;date

Команда не является условно безопасной (как есть), потому что единственный возможный результат из $ # - число. И единственный возможный результат $ n (где n - число) - это содержимое такой позиционной переменной.

Если вы хотите увидеть, что делает команда, замените eval на echo

$ set -- "ls -l" "*" "c; date"
$ echo echo \"\$\{$#\}\"          ### command under test
echo "${3}"

А echo $ {3} - очень распространенная (и безопасная) идиома.

Мы все еще можем изменить некоторые цитаты и получить тот же результат:

$ echo echo '"${'$#\}\"
echo "${3}"
$ eval echo '"${'$#\}\"
c;date

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

Немного другая идиома.

$ b=book
$ book="A Tale of Two Cities"
$ eval 'a=$'"$b"               ### safe for some values of $b.
$ echo "$a"
A Tale of Two Cities

И здесь мы находим первую (из двух) и основную проблему с eval:
недостаточное цитирование:

$ b='book;date'

$ eval 'a=$'"$b"               ### safe for some values of $b.
Fri Apr 22 22:03:09 UTC 2016

Дата команды была выполнена (чего мы не собирались).

Но это не выполнит дату (по крайней мере, я так подумал, спасибо @Wildcard).
Правильным решением этой команды является очистка ввода, но я отложу обсуждение этого вопроса до тех пор, пока не будет определена вторая проблема eval.

$ eval 'a="$'"$b"\"
$ echo "$a"
A Tale of Two Cities;date

Уловка несложная, просто замените eval на echo и оцените, безопасна ли напечатанная командная строка. Сравните небезопасную и безопасную команду:

$ echo 'a=$'"$b"
a=$book;date
$ echo 'a="$'"$b"\"
a="$book;date"

Эти простые двойные кавычки сохранят строку как строку и не будут преобразованы в команду для выполнения оболочкой.

Возможно, будет легче понять логику цитирования, если мы поместим «внешние кавычки» и «внутренние кавычки» (добавлены пробелы для разборчивости):

$ echo a\=\"\$    "$b"   \"

Внутренние кавычки - это те, которые находятся вокруг $ b которые всегда являются «хорошей идеей».
Все внешние обозначены обратной косой чертой (в этом примере).
Команда без пробелов (как и следовало бы использовать):

$ echo a\=\"\$"$b"\"
a="$book;date"

$ eval a\=\"\$"$b"\"
$ echo "$a"
A Tale of Two Cities;date

Но даже этот пример был очень быстро сломан пользователем (спасибо @Wildcard):

$ b='";date;:"'
$ eval a\=\"\$"$b"\"
Fri Apr 22 23:25:43 UTC 2016

Выполнение команды eval было прервано стать злым, давайте использовать echo:

$ echo a\=\"\$"$b"\"
a="$";date;:""

Думать о том, что является результатом двойного цитирования, никогда не бывает просто.

Вторая проблема.

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

Или злоумышленник (как уже было показано выше) создает строку, которая соответствует квотам, а затем помещает команду вне кавычек. Команда будет выполнена, и (если нам повезет) будет сообщено об ошибке.

Это нарушает первый уровень защиты: цитирование
И оставляет значения переменных полностью открытыми для выполнения.

В этом случае обязательно, чтобы мы были уверены в значениях, которые будет иметь переменная. Все возможные значения.

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

Дайте мне любую команду, я выполню ее с моими разрешениями.

Это всегда опасная ставка, верный баг, а корень - безумный поступок.

Очистка внешних данных.

Сказав все вышесказанное, это совершенно безопасно:

#!/bin/bash

a=${1//[^0-9]}       ### Only leave a number (one or many digits).

eval echo $(( a + 1 ))

Независимо от того, что внешний пользователь поместил в позиционный параметр, он станет числом, это может быть большое число, для которого $ ((...)) завершится ошибкой, но этот ввод не вызовет выполнение какой-либо команды.

Теперь мы можем поговорить об очистке переменной b из приведенной выше команды. Команда была:

$ b='";date;:"'
$ eval a\=\"\$"$b"\"
Sat Apr 23 01:56:30 UTC 2016

Потому что b содержало несколько символов, которые использовались для изменения строки.

$ echo a\=\"\$"$b"\"
a="$";date;:""

Переход на одинарные кавычки не сработает, им может соответствовать другое значение b. Нам нужно «очистить» b , удалив (как минимум) кавычки.
Мы могли бы заменить $ b на $ {b // \ "} :

$ eval a\=\"\$"${b//\"}"\"
$ echo "$a"
$;date;:

Более надежная очистка имени переменной.

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

$ c="$( LC_COLLATE=C; echo "${b//[^0-9A-Za-z_]}" )"

Это очистит переменную b на допустимое имя переменной.
А затем мы можем добавить еще более строгую проверку, фактически проверив, что имя переменной внутри $ b (используя очищенный ] c ) существует:

$ if declare -p "$c" &>/dev/null; then   eval a\=\"\$"$c"\" ; fi
4
14.12.2015, 10:32
0 ответов

Теги

Похожие вопросы