Аутентификация пользователей через Веб-интерфейс
Про аутентификацию пользователей написано масса статей и для оной
процедуры изготовлено сотни скриптов.
Однако, в большинстве своем все
эти методы рассчитаны на хранение логинов/паролей в отдельном файле, или
на аутентификацию пользователей с помошью апачесвкого .htaccess.
Здесь
же речь пойдет про аутентификацию реальных пользователей Unix сервера
через веб-интерфейс.
Есть довольно много методов для решения этой
задачи, но используют в основном два способа:
- шифруют пароль, введенный в веб-форме и сравнивают его с паролем в файле passwd или shadow
- используют pop3 аутентификацию.
Первый метод весьма скользкий, ибо его реализация требует прав
суперпользователя (root) для открытия файла зашифрованных паролей
(shadow), и, как следствие, является дырой в безопасности сервера. Он
реализуется путем исполнения cgi-скрипта с правами root
(suid).
Вообщем, алгоритм простой:
- взять пару логин/пароль с Web-формы;
- зашифровать пароль тем же алгоритмом, что и на сервере;
- открыть файл shadow для сравнения пароля, там хранящегося с полученным с web-формы.
- Ежели результат сравнения положителен, аутентификация прошла успешна и увы в противном случае.
- Не забыть позакрывать все файлы.
Все вообщем-то довольно просто.
Открыли файл, прочитали в буфер,
нашли нужную нам строчку, закриптовали пароль, сравнили с тем, что в файле
и по делам ихним воздаем аутентифицирующемуся юзеру.
В Unix системах
шифрование происходит в одну сторону - к зашифрованному паролю
добаваляется хорошая порция избыточной информации (salt - соли), и
выдернуть пароль назад оттуда не представляется возможным. Так что,
"взлом" паролей возможен лишь методом подбора оного. Ну, а если
пользователь легальный и пароль действительный, то зашифруя его, мы сразу
же успешно проходим аутентификацию.
За что мне нравится Perl, так это
ненужность изобретать велосипеды.
проверка пароля сводится к вызову
стандартной системной функции crypt($text,$salt). Действует она так :
в
качестве параметров подается пароль в "чистом" виде и зашифрованный, на
выходе она должна выдать тот же зашифрованный пароль. Если этого не
произошло, значит пароль в виде простого текста был неправильный.
В
общем вся процедура выглядит все где-то так:
#!/usr/bin/suidperl # # читаем форму ......... &check_passwd; sub check_passwd { my $shadow = "/etc/shadow"; # ниже две строчки = переданные из формы пароль/логин $plaintext = $form{'password'}; $username = $form{'login'}; # пытаемся открыть файл зашифрованных паролей (на нормальной системе # он доступен только для чтения только root-ом.) # и заодно попытаемся его залочить. open (SHADOW, "<$shadow") or die "Internal system error: $!"; flock (SHADOW, 2) or die "Internal lock error: $!"; @shadows=; flock SHADOW, 8; # закроем shadow close SHADOW; foreach $line(@shadows) { chomp($line); ($currentuser, $currentpass, $restofline) = split /:/, $line, 3; if ($currentuser eq $username) # Выдергиваем зашифрованный пароль из shadow $saltedpass = $currentpass; # Проверяем его стандартной функцией crypt if ( crypt ($plaintext, $saltedpass) eq $saltedpass) { print "Authentification for $username success!\n"; } else { print "Authentification for $username failure!\n"; } } } }
Файлу, содержащему сей "шедевр" программистского искусства следует в
целях безопасности установить атрибуты:
Владелец - root
Взведенный
бит установки ID пользователя при исполнении режим доступа
r-sr-xr-x
грубо говоря, в восьмеричном отображении оно будет выглядеть
как 104555
В этом suid-e и кроется опасность, - если кто-то умудрится
всунуть кусок своего кода в вашу программу, то сможет получить доступ к
вашей системе.
(Для неверующих - прочитайте что-нибудь про Ramen -
он еще и не то делает/делал).
А посему сей метод, как
небезопасный, лучше не использовать.
Лучше взять готовую
Perl-библиотеку: Net.
POP3 Аутентификация
Простой и безопасный метод проверки подлинности
пользователя.
Берется библиотека Net::POP3 и стандартными методами
пытаемся влогиниться в почтовый ящик. Если нам это удалось, то
логин/пароль верны, и обратный результат в ином случае.
Модуль
Net::POP3 дает пользователю создать объект и 14 методов к нему.
Все
методы изучать нет смысла - они довольно-таки неподробно описаны в
документации к модулю, нас более интересует метод
login($user,$passwd).
Он возвращает значение undef в случае неудачной
аутентификации, или, в случае удачного входа в почтовый ящик, количество
писем в оном, или строку "0E0", если писем нет , т.е.
"пишут".
Порядок работы с ним следующий:
use Net::POP3; &parse_form # Читаем из формы переданные пароль/логин # Создаем объект $pop = Net::POP3->new('popserver') || print "Cannot create connection\n"; # пробуем влогиниться # в $res будет возвращен результат логина $res = $pop->login($form{'login'},$form{'password'}); if ($res == undef) { # неудача print "Incorrect username or password!\n"; } else { # влогинились # делаем, что надо # # следующий код нарисован для того, чтобы хоть что-то # делалось. if ($res eq "0E0") { # писем нет print "You have $res messages in mailbox.\n"; } else { # письма есть print "You have $res messages in mailbox.\n"; } } #закрываем соединение. $pop->quit();
Намного проще и безопаснее, чем лезть в святая святых безопасности Unix
систем- файл shadow.
Да и не нужно просить сисадмина сервера установить
на ваш скрипт setuid bit, хотя заранее можно сказать, что любой нормальный
сисадмин вам в этом откажет, и будет на все сто прав.
А библиотека Net
есть практически на любом Web-сервере, где есть доступ к perl
интерпретатору.