Ставим пароль на страницуДанная статья не претендует на какие-то откровения, все эти вещи достаточно очевидны и широко известны. Но получив за последнее время несколько вопросов об ограничении доступа к web-страницам, я решил свести ответы на них вместе. Итак, наша задача - установить пароль на доступ к некоторой странице. Начнем с самого примитивного способа, если можно так сказать, защиты - нескольких строчек на JavaScript'е. Код - что-то вроде var pass = prompt("Enter the Password:", ""); if (pass == null) window.location = "bad.html"; else if (pass.toLowerCase() == "password") window.location = "ok.html"; else window.location = "bad.html"; Уровнем повыше расположена аналогичная система, реализованная на Java. Ниже приведен упрощенный исходный код. import java.applet.*; import java.awt.*; import java.net.*; public class Password extends Applet { TextField login, password; String Login = "login"; String Password = "Password"; public Password() { } public void init() { Panel panel = new Panel(); panel.setLayout(new GridLayout(2,2)); login = new TextField(20); password = new TextField(20); panel.add(new Label("Login:")); panel.add(login); panel.add(new Label("Password:")); panel.add(password); add(panel); add(new Button("Ok")); } public boolean action(Event evt, Object obj) { if(evt.target instanceof Button) { String s; if(login.getText().equals(Login) && password.getText().equals(Password) ) { s = "h t t p://www.webclub.ru/materials/pagepsw/ok.html"; } else { s = "h t t p://www.webclub.ru/materials/pagepsw/bad.html"; } try { getAppletContext().showDocument(new URL(s)); } catch(Exception e) { password.setText(e.toString()); } return true; } return false; } } Включив этот апплет в страницу, можно получить нечто такое:
Его можно сделать поумнее, завести для каждого пользователя отдельную страницу, заставить считывать данные из файла и т.д. Принципиальный недостаток - после того как человек попал на искомую страницу, никто не в силах запретить ему запомнить этот URL, так что средство это одноразовое. Конечно, можно запрятать страницу внутрь фрейма, чтобы URL не светился в строке адреса, но сами понимаете, от кого эта защита. Опять же, апплет полностью уходит к клиенту и в принципе полностью доступен для исследования. Последнего недостатка лишено решение, основанное на использовании CGI. Простенький скрипт на Perl'е выглядит примерно так: #!/usr/bin/perl use CGI qw(:standard); $query = new CGI; $ok = 'ok.html'; $address = 'bad.html'; $login = "login"; $password = "password"; $l = $query->param("login"); $p = $query->param("password"); if(($p eq $password) && ($l eq $login)) { $address = $ok; } print $query->redirect($address); Пример использования:
Чтобы справиться с первым недостатком, можно динамически сформировать новую страницу на основе спрятанной где-то там внутри, не выдавая при этом URL. Модифицированный код:
#!/usr/bin/perl use CGI qw(:standard); $query = new CGI; $ok = 'ok.html'; $address = 'bad.html'; $docroot = $ENV{'DOCUMENT_ROOT'}; $localpath = "/materials/pagepsw/"; $login = "login"; $password = "password"; $l = $query->param("login"); $p = $query->param("password"); if(($p eq $password) && ($l eq $login)) { $address = $ok; } print $query->header(); open (FL, $docroot.$localpath.$address); while(<FL>) { # Здесь заодно можно на лету модифицировать html-код # Зачем ? Ну мало ли... :) print $_; } close (FL); Пример использования:
Как видно, URL файла уже не светится, правда ценой SSI, если что-то подобное присутствовало (впрочем, это как раз можно отлавливать при выводе и обрабатывать вручную). Но и здесь остается теоретическая возможность угадывания URL, при этом не надо забывать, что медвежью услугу могут сослужить всевозможные картинки, включаемые в страницы - при использовании относительных путей, конечно. Наконец, наиболее надежный способ установки пароля на доступ - это воспользоваться средствами сервера - не зря ж их люди делали, в конце концов. Остановлюсь на двух - Апаче как самом популярном и IIS как тоже популярном :) С IIS все совсем просто - защита осуществляется средствами NTFS, что, конечно, несколько ограничивает возможности не-администраторов сервера. Идея следующая: у пользователя IUSR_xxxx, под аккаунтом которого по умолчанию работают все посетители узла, отбирается доступ к желаемому файлу/каталогу. После чего доступ к этим файлам будут иметь только те пользователи, для которых это явно указано в Properties->Security. Понятно, что их гораздо удобнее объединять в группы. Здесь есть пара тонкостей. Во-первых, указанным пользователям должно быть дано право Logon locally (Policies->User Rights в User Manager'е). Во-вторых, если не выбрать в настройках WWW service Basic authentication (Clear Text), внутрь будут пропущены только пользователи Internet Explorer'а. В Apache все делается несколько иначе. Защита ставится на уровне каталогов. Соответствующие директивы могут быть помещены как в в общий конфигурационный файл (в разделе <Directory>), так и в файлы .htaccess. Набор директив в обоих случаях одинаков, а для большинства людей, арендующих место под сайт/страницу на чужом сервере, гораздо актуальнее второй способ. Итак, вы создаете в каталоге, доступ к которому планируется ограничить, файл .htaccess, после чего вставляете в него следующие директивы (привожу основные): AuthType тип контроля - обычно используется Basic. AuthName имя - задает имя области, в которой действительны имена и пароли пользователей. Это то самое имя, которое броузер показывает в диалоге ввода пароля. Задав одно такое имя для разных каталогов, можете сэкономить пользователям время по вводу лишнего пароля. AuthGroupFile имя - задает имя
файла, в котором хранятся имена групп и их членов. Его формат: AuthUserFile имя - задает имя
файла с паролями. По большому счету для его формирования надо воспользоваться
утилитой htpasswd из поставки Apache. Но по крайней мере для некоторых версий
сервера этот формат такой: Passwordhash вполне можно получить стандартной
функцией Perl'а: Так что вполне можно автоматизировать процесс добавления новых пользователей, смену паролей через html-формы и т.д. require user user1 user2 и require group user1 user2 позволяют указать, какие пользователи и группы получат доступ к данному каталогу. require valid-user разрешает доступ всем пользователям, указанным в файле паролей системы. <Limit method1 method2 ...> ... </Limit> , где methodi определяет HTTP-метод. Например, <Limit GET POST> ограничивает применение вложенных в нее директив случаями использования методов GET и POST (обычно этого более чем достаточно). Вложенными могут быть директивы require, order, allow и deny. Еще пара полезных директив - deny и allow -
соответственно запрещения и разрешения доступа. Применяются примерно так: По умолчанию сначала выполняются все deny, потом все allow, так что allow from all разрешит доступ всем пользователям, невзирая ни на какие deny. Порядок можно изменить директивой order: order allow, deny. deny from all отлично сочетается со вторым способом защиты страниц через CGI, именно этой директивой лучше всего прикрывать всякие пароли к гостевым книгам и т.д. Кстати, тут между делом демонстрируется самостоятельная
обработка ошибок: в данном случае - код 403, Forbidden. Аналогично обрабатывается
и всеми любимая 404, Not Found, и 401, Unauthorized. Для этого достаточно добавить
в .htaccess директиву ErrorDocument код url: Все, что делает скрипт - формирует сообщение об ошибке, используя переменную окружения REQUEST_URI, так что всместо него вполне можно просто указать какую-нибудь подходящую страницу. Для заключительного примера используем файл .htaccess со следующим содержимым: AuthType Basic AuthName Test AuthGroupFile /.../pagepsw/deny/tgroup AuthUserFile /.../pagepsw/deny/tuser <Limit GET POST> require group test </Limit> В файле tgroup всего одна строчка - test: login test, в файле tuser - зашифрованные пароли для login (password) и test (test). Обратите внимание, при повторном обращении к этой странице броузер понимает, что только что обращался к этой области, и не утруждает пользователя лишним запросом пароля. Таков вкратце минимальный набор сведений, необходимых для защиты web-страниц. Как показывает практика, более-менее доверять стоит лишь решениям, основанным на средствах, предоставляемых сервером (и то до тех пор, пока в сервере не обнаружится очередная дырка), так что если есть возможность, лучше выбирать именно их. Поделитесь этой записью или добавьте в закладки | Полезные публикации |