Ответ 1
Да, вам следует избегать использования sh -c
и эквивалентов в ваших сценариях оболочки, так же, как вы избегаете eval
.
eval "$foo"
... заключается в том, что когда он сводится к минимуму, возникает риск безопасности, поскольку он обрабатывает данные как код, перезапуская процесс разбора в самом начале (таким образом, запуская расширения, перенаправления и т.д.). Более того, поскольку цитирующие контексты рассматриваются в этом процессе, содержимое внутри оцениваемых данных способно избежать кавычек, прекращать команды и в противном случае пытаться избежать любых усилий, предпринятых при обеспечении безопасности.
sh -c "$foo"
делает то же самое - запускает расширения, перенаправления и т.п. - только в совершенно новой оболочке (не используя неэкспонированные переменные или другое состояние).
Оба из них означают, что контент, такой как $(rm -rf /)
, подвержен расширению, если не будет предпринята большая осторожность, вместо того, чтобы гарантировать, что, как это обычно бывает, данные будут обрабатываться только как данные, основополагающий элемент написания защищенного кода.
Теперь, счастливая вещь заключается в том, что, когда вы используете bash
(или zsh или ksh93), а не sh
, вы можете избегать использования eval
почти во всех случаях.
Например:
value=$(eval "echo \$$varname")
... можно заменить на:
value=${!varname}
... и в bash,
eval "$varname="'$value'
... можно заменить на...
printf -v varname %s "$value"
... и т.д. (с ksh93 и zsh, имеющими прямые эквиваленты последним); более продвинутые формулировки с участием ассоциативных карт и т.
Примечательно, что bash -c
не эффективно заменяет eval
в большинстве приведенных выше примеров, потому что он не работает в том же контексте: Изменения, внесенные в состояние оболочки, выбрасываются, когда дочерний процесс завершается; таким образом, не только bash -c
не покупает безопасность, но не работает как замена eval
для начала.