Написание безопасных программ CGI
Проблема
Поскольку сценарий CGI позволяет внешнему пользователю запускать программы на недоступном
для него компьютере, любая программа CGI представляет потенциальную угрозу для безопасности.
Вам хотелось бы свести эту угрозу к минимуму.
Решение
- Воспользуйтесь режимом пометки (флаг -Т в строке #!).
- Не снимайте пометку с данных (см. ниже).
- Проверяйте все, в том числе возвращаемые значения всех элементов формы, даже скрытые
элементы и значения, сгенерированные кодом JavaScript. Многие наивно полагают — раз они
приказали JavaScript проверить значения полей формы перед отправкой данных, то значения
действительно будут проверены. Ничего подобного. Пользователь может тривиально обойти
ограничения — запретить JavaScript в своем броузере, загрузить форму и модифицировать
JavaScript или общаться на уровне HTTP без броузера.
- Проверяйте значения, возвращаемые системными функциями.
- Помните о возможности перехвата (см. ниже).
- Используйте флаг -w и директиву use strict, чтобы застраховаться от неправильных
допущений со стороны Perl.
- Никогда не запускайте сценарий со сменой прав, если только это не вызвано абсолютной
необходимостью. Подумайте, не будет ли достаточно сменить идентификтор группы. Любой
ценой избегайте запуска с правами администратора. Если вам приходится использовать
setuid или setgid, используйте командный интерпретатор, если только на вашей машине
нельзя безопасно запускать сценарии Perl с setuid и вы точно знаете, что это такое.
- Всегда шифруйте пароли, номера кредитных карт, номера социального страхования и
все остальное, что обычно не печатается на первых страницах местных газет. При работе
с такими данными следует использовать безопасный протокол SSL.
Комментарий
Многие из этих рекомендаций подходят для любых программ — флаг -w и проверка значений,
возвращаемых системными функциями, пригодятся и в тех ситуациях, когда безопасность не
является первоочередной заботой. Флаг -w заставляет Perl выводить предупреждения о
сомнительных конструкциях (например, когда неопределенная переменная используется так,
словно ей присвоено законное значение, или при попытке записи в манипулятор, доступный
только для чтения).
Самая распространенная угроза безопасности (не считая непредвиденных вызовов
командного интерпретатора) кроется в передаче форм. Кто угодно может сохранить исходный
текст формы, отредактировать HTML-код и передать измененную форму. Даже если вы уверены,
что поле может возвращать только "yes" или "no", его всегда можно отредактировать и
заставить возвращать "maybe". Даже скрытые поля, имеющие тип HIDDEN, не защищены от
вмешательства извне. Если программа на другом конце слепо полагается на значения полей,
ее можно заставить удалять файлы, создавать новые учетные записи пользователей, выводить
информацию из баз данных паролей или кредитных карт и совершать множество других
злонамеренных действий. Вот почему нельзя слепо доверять данным (например, информации
о цене товара), хранящимся в скрытых полях при написании приложений CGI для электронных магазинов.
Еще хуже, если сценарий CGI использует значение поля формы как основу для выбора
открываемого файла или выполняемой команды. Ложные значения, переданные сценарию,
заставят его открывать произвольные файлы. Именно из-за таких ситуаций в Perl появился
режим помеченных данных. Если программа выполняет setuid или имеет активный флаг -Т,
то любые данные, получаемые ею в виде аргументов, переменных окружения, списков
каталогов или файлов, считаются ненадежными и не могут прямо или косвенно воздействовать на внешний мир.
В этом режиме Perl настаивает на том, чтобы переменная пути задавалась заранее,
даже если при запуске программы указывается полный путь. Дело в том, что нельзя быть
уверенным, что выполняемая команда не вызовет другую программу по относительному
имени. Кроме того, вы должны снимать пометку со всех внешних данных.
Например, при выполнении в режиме пометки фрагмента:
#!/usr/bin/perl -Т
open(FH, "> $ARGV[0]") or die;
Perl выдает следующее предупреждение:
Insecure dependency in open while running with -T switch at ...
Это объясняется тем, что значение $ARGV[0] (поступившее в программу извне)
считается не заслуживающим доверия. Единственный способ снять пометку с ненадежных
данных — использовать обратные ссылки в регулярных выражениях:
$file = $ARGV[0]; # $file помечена
unless ($file =~ m#^([\w.-]+)$#) { # С $1 снята пометка
die "filename '$file' has invalid haracters.\n";
}
$file = $1; # С $file снята пометка
Помеченные данные могут поступать из любого источника, находящегося вне программы, —
например, из аргументов или переменных окружения, из результатов чтения файловых или
каталоговых манипуляторов, команды stat или данных о локальном контексте. К числу операций,
которые считаются ненадежными с помеченными данными, относятся: system(CTPOKA),
exec(CTPOKA),
'...',
glob,
open в любом режиме, кроме «только для чтения»,
unlink,
mkdir,
rmdir,
chown,
chmod,
umask,
link, symlink, флаг командной строки -s,
kill,
require,
eval,
truncate, ioctl,
fcntl,
socket, socketpair,
bind,
connect,
chdir,
chroot,
setgrp, setprionty и syscall.
Один из распространенных видов атаки связан с так называемой ситуацией перехвата
(race condition). Ситуация перехвата возникает тогда, когда нападающий вмешивается между
двумя вашими действиями и вносит какие-то изменения, нарушающие работу программу.
Печально известная ситуация перехвата возникала при работе setuid-сценариев в старых
ядрах UNIX. Между тем как ядро читало файл и выбирало нужный интерпретатор и чтением
файла интерпретатором после setuid злонамеренный чужак мог подставить свой собственный сценарий.
Ситуации перехвата возникают даже во внешне безобидных местах. Допустим, у вас
одновременно выполняется не одна, а сразу несколько копий следующего кода:
unless (-e $filename) { # НЕВЕРНО!
open(FH, "> $filename");
# ...
}
Между проверкой существования файла и его открытием для записи возникает возможность
перехвата. Что еще хуже, если файл заменится ссылкой на что-нибудь важное (например, на
ваш личный конфигурационный файл), предыдущий фрагмент сотрет этот файл. Правильным
решением является неразрушающее создание функцией sysopen.
Setuid-сценарий CGI работает с другими правами, нежели Web-сервер. Так он получает
возможность работать с ресурсами (файлами, скрытыми базами данных паролей и т. д.), которые
иначе были бы для него недоступны. Это может быть удобно, но может быть и опасно. Из-за
недостатков setuid-сценариев хакеры могут получить доступ не только к файлам, доступным для
Web-сервера с его низкими привилегиями, но и к файлам, доступным для пользователя, с правами
которого работает сценарий. Плохо написанный сценарий, работающий с правами системного
администратора, позволит кому угодно изменить пароли, удалить файлы, прочитать данные кредитных
карт и совершить иные злодеяния. По этой причине программа всегда должна работать с
минимальным возможным уровнем привилегий, как правило — со стандартными для Web-сервера правами nobody.
Наконец, принимайте во внимание физический путь вашего сетевого трафика (возможно,
это самая трудная из всех рекомендаций). Передаете ли вы незашифрованные пароли? Не
перемещаются ли они по ненадежной сети? Поле формы PASSWORD защищает лишь от тех,
кто подглядывает из-за плеча. При работе с паролями всегда используйте SSL. Если вы
серьезно думаете о безопасности, беритесь за броузер и программу перехвата пакетов,
чтобы узнать, легко ли расшифровать ваш сетевой трафик.
См. также
Proverte kod v komentariyah gde pro list tam oshibki detskie
Оставить комментарий:
|
|