Безопасность сценария оболочки

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

Далее, большинство проблем безопасности является также ошибками правильности, даже если кто-то не пытается атаковать Ваш код.

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

Эта глава также описывает, как полномочия UNIX и списки управления доступом POSIX (ACLs) влияют на Ваши сценарии и как управлять теми полномочиями и ACLs в Ваших сценариях.

Атаки среды

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

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

Наиболее распространенная атака среды изменяет PATH переменная окружения. Это управление переменными, что выполняется, когда Вы вводите команду, не давая полный путь.

Рассмотрите следующий код:

#!/bin/sh
 
ls /tmp

Атака:

Создайте исполнимый двоичный файл или сценарий, делающий что-то вредное и называющий его «ls». Тогда сделайте это:

export PATH=/path/to/malicious/binary:$PATH
/path/to/above/script

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

Смягчение:

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

Атаки на файлы в публично Перезаписываемых каталогах

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

Временная атака файла

Самым простым примером этой атаки является инструмент, хранящий секретную информацию во временный файл.

Рассмотрите следующий код:

#!/bin/sh
 
SECRETDATA="My password is 12345."
echo > /tmp/mysecretdata
chmod og-rwx /tmp/mysecretdata
echo "$SECRETDATA" >> /tmp/mysecretdata

Атака:

Создайте инструмент, наблюдающий за файлом /tmp/mysecretdata появиться. (Несмотря на то, что это может быть сделано со сценарием оболочки, это, вероятно, не будет достаточно быстро для работы очень часто. Используйте События Файловой системы API в C вместо этого.)

После обнаружения существования пути сделайте это:

FILE *fp=fopen("/tmp/mysecretdata", "r");

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

Смягчение:

Существует две вещи, которые необходимо сделать для фиксации этого:

  • Всегда используйте umask команда для указания первоначальных полномочий на файле, когда Вы создаете его.

  • Всегда создавайте временные файлы с mktemp команда. Это создает новый файл с указанным шаблоном, гарантируя, что уже не существуют файл или символьная ссылка с тем именем.

Например:

#!/bin/sh
 
SECRETDATA="My password is 12345."
umask 0177
FILENAME="$(mktemp /tmp/mytempfile.XXXXXX)"
echo "$SECRETDATA" >> "$FILENAME"

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

Входная атака файла

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

Рассмотрите сценарий, выполняющий следующий код:

#!/bin/sh
 
echo "My password is secret!" > /tmp/mypublicdata
 
...
 
PUBLICDATA="$(cat /tmp/mypublicdata)"
 
echo "$PUBLICDATA" | nc 192.168.1.102 3333

Этот сценарий отправляет содержание временного файла для портирования 3333 из другого компьютера в IP-адресе 192.168.1.102 с помощью nc утилита.

Атака:

Создайте инструмент, наблюдающий за файлом /tmp/mydata появиться. (Несмотря на то, что это может быть сделано со сценарием оболочки, это, вероятно, не будет достаточно быстро для работы очень часто. Используйте События Файловой системы API в C вместо этого.)

После обнаружения существования пути сделайте это:

unlink("/tmp/mypublicdata");
unlink("/etc/myscretdata", "/tmp/mypublicdata");

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

Смягчение:

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

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

    Если Вы указываете -d флаг, mktemp команда создает новый каталог с указанным шаблоном, гарантируя, что уже не существует файл или каталог с тем именем.

  • Всегда используйте umask команда для указания первоначальных полномочий на файлах и каталогов, когда Вы создаете их.

Например:

#!/bin/sh
 
umask 0177
TMPDIR="$(mktemp -d /tmp/mytempfile.XXXXXX)"
echo "My password is secret!" > "$TMPDIR"/mypublicdata
 
...
 
PUBLICDATA="$(cat "$TMPDIR"/mypublicdata)"
 
echo "$PUBLICDATA" | nc 192.168.1.102 3333

Инжекционные атаки

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

Простой пример

Рассмотрите следующий пример:

read FOO
read BAR
if [ x$FOO = xfoo ] ; then
    echo $FOO
    eval $BAR
fi

Этот код имеет две дыры в системе безопасности. Можно ли определить их?

  • if [ x$FOO = xfoo ] ; then

    Этот оператор допускает инжекционную атаку на FOO.

    Атака:

    Передача “foo = xfoo -o x” как значение для FOO.

    Несмотря на то, что значение FOO не «foo», оператор выполняется так или иначе. В зависимости от какого этот тест делает, это могло потенциально вызвать неожиданное поведение.

    Смягчение:

    Для исправления этой ошибки изменитесь если оператор для чтения:

    if [ "$FOO" = "foo" ] ; then
  • eval $BAR

    Это нет - нет. Никогда не работайте, оценка на данных передала в пользователем, если Вы очень, очень тщательно не санировали его (и, если возможно, используйте whitelist для ограничения позволенных значений).

    Атака:

    Передайте опасную команду для BAR.

    Смягчение:

    Просто не делайте этого.

Тонкий пример

Следующий пример является более тонким. Вместо выполнения eval, это пишет данные в сценарий, но делает так, не защищая значения:

#!/bin/sh
 
read FOO
 
# ...
 
echo ls $FOO >> myscript.sh
 
# ...
 
chmod a+x myscript.sh
./myscript.sh

Атака:

Передайте значение “; rm randomfile” чтобы заставить этот сценарий удалять файл.

Неправильное смягчение:

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

echo ls "\"$FOO\"" >> myscript.sh
export FOO

Однако это все еще не решает проблему потому что FOO сразу расширен, что означает что если значение FOO содержит кавычку — например, “";rm randomfile ; echo "”, у Вас теперь есть различное (но одинаково плохо) дыра в системе безопасности.

Корректное смягчение № 1:

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

echo ls "\"\$FOO\"" >> myscript.sh

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

Корректное смягчение № 2:

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

QUOTFOO="$(echo "$FOO" | sed "s/'/'\"'\"'/g")"
echo ls "'$QUOTFOO'" >> myscript.sh

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

Назад пример совместимости

Следующий пример не опасен в современных оболочках, но опасен в более старых Оболочках Bourne:

#!/bin/sh
 
read FOO
echo $FOO

Атака:

Передайте значение “; rm randomfile” чтобы заставить этот сценарий удалять файл в более старых оболочках.

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

Смягчение:

Для исправления этой ошибки измените строку эха для чтения:

echo "$FOO"

Атаки аутентификации

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

Неправильный путь:

if [ $UID = 100 -a $USER = "myusername" ] ; then
    cd $HOME
fi

Этот код имеет три ошибки безопасности, и они все вызываются при помощи переменных способами, которые небезопасны. Для исторической совместимости OS обеспечивает UID, USER, и HOME переменные окружения. Они довольно полезны, пока Вы не используете их для соображений безопасности.

Атака:

$ tcsh
% setenv UID 100
% setenv USER myusername
% setenv HOME $HOME/.ssh
% /path/to/script.sh

Даже при том, что большинство современных Оболочек Bourne защищает от изменения UID, USER переменная незащищена, и не все оболочки защищают UID переменная, также.

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

Смягчение:

Получить идентификатор пользователя:

# Effective UID
MYEUID="$(/usr/bin/id -u)"
 
# Real UID
MYUID="$(/usr/bin/id -u -r)"

Получить имя пользователя:

MYUID="$(/usr/bin/id -u -n)"

Получить фактический корневой каталог:

HOMEDIR="$(dscl . -read /Users/dg NFSHomeDirectory | sed 's/^NFSHomeDirectory: //')"

Обратите внимание на то, что этот метод для получения корневого каталога является определенным для OS X.

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

OS X использует модель полномочий UNIX, расширенную списками управления доступом POSIX. Эти модели полномочий описаны подробно в разделе OS X File System Security Руководства по программированию Файловой системы. Этот раздел предполагает, что Вы уже, по крайней мере, периферийно знакомы с понятием о пользователях и группах.

Исследование полномочий файла

Полномочия UNIX видимы пользователям в Терминале и в окне Finder's Get Info. В Терминале можно легко смотреть на полномочия в человекочитаемом формате при помощи ls команда следующим образом:

$ ls -ld filename dirname
drwxr-xr-x  2 username  groupname  68 Jun 16 13:40 dirname
-rw-r--r--  1 username  groupname   0 Jun 16 13:40 filename

Левый символ указывает, является ли объект файловой системы файлом (-), каталог (d), символьная ссылка (l), блок (b) или символ (c) специальный файл, именованный канал (p), или сокет домена UNIX (s).

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

Флаг Permissions

Восьмеричное битовое значение

Значение

-

n/a

Никакое разрешение

r

4

Считайте разрешение

w

2

Запишите разрешение

x

1

Выполните разрешение

s

В дополнительной первой восьмеричной цифре:

  • 4 — setuid

  • 2 — setgid

Setuid или setgid с выполняют разрешение

S

Посмотрите выше.

Setuid или setgid without выполните разрешение

t

В дополнительной первой восьмеричной цифре:

1

Липкий бит

Полный набор полномочий часто выражается в восьмеричном, как определено битами в таблице выше. Первая цифра включает липкий бит и setuid и setgid биты. Если нуль, можно опустить его при передаче значения большинству команд. Оставление тремя цифрами содержит Владельца (пользователь), Группа и Другие полномочия, соответственно.

Например, файл, который является setuid и setgid, с, читал/писал/выполнял полномочия Владельца и читал/выполнял Группу и Другие полномочия, восьмеричный эквивалент 6755:

  • Ведущее специальное значение полномочий равняется 6, который является битовым «ИЛИ» setuid (4) и setgid (2).

  • Разрешение Владельца равняется 7, который является битовым «ИЛИ» чтения (4), запишите (2) и выполнитесь (1) биты.

  • Группа и Другие полномочия и 5, который является битовым «ИЛИ» чтения (4), и выполнитесь (1) полномочия.

Для показа полномочий UNIX файла используйте команду статистики следующим образом:

stat -f "%p" filename

Проигнорируйте все кроме последних четырех цифр возвратились.

Изменение принадлежности файла и полномочий

Возможность изменить принадлежность файла и полномочия ограничивается операционной системой по причинам квоты и безопасности. Пользователи могут:

  • Измените полномочия для любого файла, которым они владеют.

  • Измените группу для любого файла, которым они владеют любой группе, из которой они являются участником.

Некорневые пользователи не могут:

  • Полномочия изменения на файлах принадлежат кому-либо еще.

  • Измените группу файла группе, из которой они не являются участником.

  • Измените владельца любого файла.

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

С теми ограничениями в памяти, следующие разделы описывают, как изменить полномочия и изменить пользователя и владение группы файлов и каталогов.

Используйте chown и chgrp для Изменения Владения Групп и Пользователя

Можно изменить владельца файла или каталога с chown команда:

# Change the owner of a file or directory
sudo chown newowner filename_or_dirname
 
# Change the owner of a directory and everything in it recursively
sudo chown -R newowner dirname

Можно изменить группу для файла с любым chown команда или chgrp команда:

# Change the group by itself
chown :newgroup filename_or_dirname
chgrp newgroup filename_or_dirname
 
# Change the group of a directory and everything in it recursively
chown -R :newgroup dirname
chgrp -R newgroup dirname

Можно также изменить и владельца и группу одновременно:

# Change the owner and the group
sudo chown newowner:newgroup filename_or_dirname
 
# Change the group of a directory and everything in it recursively
sudo chown -R newowner:newgroup dirname

Для получения дополнительной информации см. страницы руководства для chown и chgrp.

Используйте chmod для Изменения Полномочий Файла и Каталога

OS X (и другие основанные на UNIX операционные системы) обеспечивает chmod команда для изменения полномочий файлов и каталогов.

chmod команду, короткую для “режима изменения”, так называют, потому что это позволяет Вам изменять режимы файла или каталога. Режим является трехразрядным или четырехразрядным восьмеричным представлением полномочий UNIX для файла (или 4-5 цифр на языках, требующих начального нуля, такого как C).

Существует два основных способа, которыми можно использовать chmod команда: числовые режимы и человекочитаемые флаги.

Большая часть пользовательского использования chmod в его человекочитаемой форме:

chmod a+rw world_writable_file

Эта команда говорит chmod добавить чтение (r) и запишите (w) доступ к существующему набору полномочий для всех пользователей (a). Таким образом, если полномочия были первоначально r-x--x-w-, получающиеся полномочия были бы rwxrwxrw-.

Можно также добавить и вычесть полномочия для пользователя владения (u), группа (g), или другие пользователи (o) отдельно. Например, для добавления чтения (r), запишите (w), и выполнитесь (x) разрешение для пользователя владения и устраняет его от участников группы владения и всех остальных, Вы могли дать любую из следующих команд:

chmod u+rwx,g-rwx,o-rwx filename
chmod u+rwx,go-rwx filename
chmod a-rwx,u+rwx filename

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

chmod g=r filename

Наконец, чтобы заставить исполнимую программу выполнить setuid (u+s) и setgid (g+s), Вы могли бы выполнить команду как одно из следующего:

chmod a+rx,ug+s filename
chmod a+rxs filename    # Note: o+s is ignored.

Также, если Вы знаете числовой режим файла, Вы хотите применяться (см. Полномочия Файла Исследования для подробных данных), можно передать chmod команда или трехразрядное или четырехразрядное значение режима:

chmod 666 world_writable_file
chmod 0666 world_writable_file

chmod команда может также использоваться для изменения списков управления доступом POSIX (ACLs). Это использование описано позже в Использовании chmod для Изменения Списков управления доступом.

Используйте chflags для Установки Специальных Флагов Разрешения Файла

В дополнение к стандартным флагам разрешения OS X имеет несколько специальных флагов разрешения, которые могут быть установлены с помощью chflags или lchflags команда (или с chflags или fchflags API в C). Эти флаги описаны в разделе OS X File System Security Руководства по программированию Файловой системы.

Набор флагов полномочий с chflags имейте приоритет по любым разрешениям, данным нормальными полномочиями UNIX или списками управления доступом.

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

chflags uchg filename # user flag
sudo chflags schg filename # system flag

Заметьте, что флаг прибывает в два варианта: пользовательский флаг и системный флаг. Пользовательский флаг может быть изменен владельцем файла и root (точно так же, как нормальные полномочия). Системный флаг может быть изменен исключительно root.

Для отмены этого изменения Вы дали бы одну из следующих команд:

chflags nouchg filename # user flag
sudo chflags noschg filename # system flag

По межплатформенным причинам совместимости и удобочитаемости OS X поддерживает два других изменения на каждом из этих флагов: uchange, uimmutable, schange, и simmutable. Эти варианты ведут себя тождественно к их сокращенным формам.

Существует несколько других флагов, которые можно установить с chflags команда, наиболее распространенное существо пользователь и системные флаги только добавления (uappnd/uappend и sappnd/sappend, соответственно).

Для получения дополнительной информации читайте chflags и lchflags страницы руководства и раздел OS X File System Security Обзора безопасности.

Используйте chmod для Изменения Списков управления доступом

chmod команда обычно известна ее возможностью изменить полномочия UNIX. Однако в OS X, это также удваивает режим работы, обеспечивая интерфейсы сценариев для изменения списков управления доступом POSIX файла (ACLs).

Фундаментальное понятие ACLs является довольно прямым. Список управления доступом является списком правил (элементы списка управления доступом или ACEs).

  • Каждая запись предоставляет или отклоняет право получить доступ к файлу или каталогу определенным способом (право считать файл, например).

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

  • Если конец списка достигнут, ничего не соответствуя, полномочия UNIX файла или каталога используются для определения доступа.

Это - значительно упрощенное объяснение; для полного изложения считайте раздел OS X File System Security Обзора безопасности.

Каждая запись ACL похожа на это:

username grant rightname
groupname grant rightname
username deny rightname
groupname deny rightname

где имя пользователя и groupname являются именами пользователя или группы, соответственно, и rightname является именем права доступа (read, например).

Можно добавить элемент списка управления доступом с +a флаг к chmod. Например, для отклонения доступа для чтения на файле пользователю MySQL Вы ввели бы:

chmod +a "_mysql deny read" filename

Для наблюдения результатов изменений введите:

ls -le filename

По умолчанию новые записи списка управления доступом добавляются до конца списка. Если необходимо вставить управление доступом в другом месте в список, можно использовать +a# флаг. Например, для вставки нового правила в нуле позиции (верхняя часть списка) Вы дали бы команду как этот:

chmod +a# 0 "_www deny read" filename

Можно удалить элемент списка управления доступом с -a отметьте как это:

chmod -a "_mysql deny read" filename

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

Наконец, можно заменить запись другой записью с помощью =a# флаг. Например, для изменения имени пользователя в правиле, вставленном выше от _www к _mdnsresponder, Вы ввели бы:

chmod =a# 0 "_mdnsresponder deny read" filename

В дополнение к основным правилам, описанным выше, система ACL в OS X поддерживает наследование. Любой наследовался, записи ACL для каталога автоматически копируются в любые новые файлы, создаваемые в том каталоге во время создания.

Можно указать:

  • должен ли ACL быть наследован:

    • вложенные файлы —file_inherit право

    • каталоги —directory_inherit право

    • оба —file_inherit,directory_inherit право

    • ни один (значение по умолчанию).

  • должен ли ACL быть наследован дочерними элементами вложенных каталогов (значение по умолчанию) или не (limit_inherit право).

  • должен ли ACL примениться к самому каталогу (значение по умолчанию) или просто быть наследован вещами в нем (only_inherit право).

Можно указать любую комбинацию этих флагов в элементе списка управления доступом для каталога путем передачи флагов как части списка прав.

Например:

chmod +a "_www deny list,search,directory_inherit" dirname

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

Для получения дополнительной информации о схеме ACL в OS X описан в разделе OS X File System Security Обзора безопасности. Для получения дополнительной информации о флагах командной строки для получения и установки ACLs, см. страницу руководства для chmod.

Обеспечение временных файлов

Поскольку временные каталоги в OS X и других основанных на UNIX операционных системах являются мировыми перезаписываемыми, необходимо заботиться, чтобы гарантировать изменение файла, Вы думаете, что изменяете.

Например, следующий код имеет две серьезных ошибки:

if [ ! -f /tmp/mytempfile ] ; then
    # Race condition here
 
    touch /tmp/mytempfile
 
    chmod u=rw,og= /tmp/mytempfile
    # Missing error check here
 
    echo My secret password is omnibus > /tmp/mytempfile
fi

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

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

Флаги, влияющие на безопасность (и правильность)

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

Кроме того, оболочка BASH обеспечивает флаг, заставляющий каналы возвращать ненулевой статус выхода, когда любая команда в цепочке каналов выходит с ошибкой вместо того, чтобы всегда возвратить статус выхода последней команды. Это также поддерживает флаг, ограничивающий эффект переменных окружения на интерпретаторе, предназначенном для использования в сценариях, которые, как ожидают, будут выполнены как привилегированный пользователь (например, root пользователь).

Обнаружение переменных сброса

По умолчанию Оболочка Bourne обрабатывает переменные сброса как пустые (в отличие от этого csh). Если Ваш сценарий ожидает, что переменная сброса для содержания значения это может привести к неправильному выполнению сценария и, в зависимости от сценария, может даже привести к дыре в системе безопасности. Для принятия мер против этого можно дать следующую команду:

set -u

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

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

set +u

Проверка статуса выхода автоматически

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

set -e

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

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

set +e

Экспорт переменных автоматически

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

Можно при желании сказать оболочке автоматически экспортировать любую переменную, которую сценарий устанавливает путем выдачи следующей команды:

set -a

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

set +a

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

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

Например, рассмотрите следующий код:

ls nonexistentfile | cat
echo $?

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

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

Как альтернатива, в BASH, можно дать следующую команду прежде, чем дать команды выше:

set -o pipefail

После выдачи этой команды статус выхода канала предоставлен самой правой командой, переставшей работать с ненулевым статусом выхода или нулем если каждая команда в цепочке каналов, из которых выходят успешно. В более раннем примере, финале echo команда распечатала бы число 1 (статус выхода ls команда).

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

set +o pipefail

Очистка среды в BASH

Для сценариев оболочки BASH (или сценарии Оболочки Bourne, работающие в BASH), который должен работать в привилегированной среде (как root пользователь, например), это - хорошая идея сказать, что оболочка к не автоматически выполняет любые файлы «команд выполнения» (.bashrc, .profile, и т.д.), который может содержать команды псевдонима, влияющие на выполнение сценария, функции, которые могут переопределить команды в Вашем сценарии или даже злонамеренные команды, которые атакующий хочет, чтобы Ваш сценарий выполнил при выполнении как root пользователь.

Для очистки среды сценария таким образом необходимо изменить строку интерпретатора сценария на следующее:

#!/bin/bash -p

В этом режиме, сценарии, на которые ссылаются ENV и BASH_ENV переменные окружения не выполняются, окружают функции, не наследованы, и SHELLOPTS переменная окружения проигнорирована.