Домой / Фейсбук / Ставим пароль на страницу. Парольная защита Html код страницы логин и пароль

Ставим пароль на страницу. Парольная защита Html код страницы логин и пароль

Итак, наша задача - установить пароль на доступ к некоторой странице. Начнем с самого примитивного способа, если можно таксказать, защиты - нескольких строчек на JavaScript:

Var pass = prompt("Enter the Password:", ""); if (pass == null) window.location = "wrong.html"; else if (pass.toLowerCase() == "wwvsfc") window.location = "temp.html"; else window.location = "wrong.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 = "http://www.hackzone.ru/articles/ok.html"; } else { s = "http://www.hackzone.ru/articles/bad.html"; } try { getAppletContext().showDocument(new URL(s)); } catch(Exception e) { password.setText(e.toString()); } return true; } return false; }}

Включив этот апплет в страницу, можно получить нечто такое (во всех последующих примерах используются ok.html и bad.html):

Password check

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

Последнего недостатка лишено решение, основанное на использовании CGI. Простенький скрипт на Perl"е выглядит примерно так:

#!/usr/bin/perluse 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);

Пример использования:

Password check

Чтобы справиться с первым недостатком, можно динамически сформировать новую страницу на основе спрятанной где-то там внутри, не выдавая при этом URL.

Модифицированный код:

#!/usr/bin/perluse CGI qw(:standard); $query = new CGI; $ok = "ok.html"; $address = "bad.html"; $docroot = $ENV{"DOCUMENT_ROOT"}; $localpath = "/articles/"; $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(){# Здесь заодно можно на лету модифицировать html-код# Зачем? Ну мало ли... :) print $_;} close (FL);

Пример использования:

Password check

Как видно, 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 все делается несколько иначе. Защита ставится на уровне каталогов. Соответствующие директивы могут быть помещены как в общий конфигурационный файл php.ini, так и в файлы.htaccess . Набор директив в обоих случаях одинаков, а для большинства людей, арендующих место под сайт/страницу на чужом сервере, первый вариант недоступен. Итак, вы создаете в каталоге, доступ к которому планируется ограничить, файл.htaccess , после чего вставляете в него следующие директивы:

AuthType тип контроля - обычно используется Basic.

AuthName имя - задает имя области, в которой действительны имена и пароли пользователей. Это то самое имя, которое броузер показывает в диалоге ввода пароля. Задав одно такое имя для разных каталогов, можете сэкономить пользователям время по вводу лишнего пароля.

AuthGroupFile имя - задает имя файла, в котором хранятся имена групп и их членов. Его формат:
group1: member1 member2 ...
group2: member3 member4 ...

AuthUserFile имя - задает имя файла с паролями. По большому счету для его формирования надо воспользоваться утилитой htpasswd из поставки Apache. Но по крайней мере для некоторых версий сервера этот формат такой:
user1:passwordhash1
user2:passwordhash2

Passwordhash вполне можно получить стандартной функцией Perl"а:
$hash=crypt($pass,$salt);
где $pass - пароль, $salt - строка из двух символов, участвующая в формировании хэша.

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

require user user1 user2 и require group user1 user2 позволяют указать, какие пользователи и группы получат доступ к данному каталогу.

require valid-user разрешает доступ всем пользователям, указанным в файле паролей системы.

... , где methodi определяет HTTP-метод. Например, ограничивает применение вложенных в неедиректив случаями использования методов GET и POST (обычно этого более чем достаточно).Вложенными могут быть директивы require, order, allow и deny.

Еще пара полезных директив - deny и allow - соответственно запрещения и разрешения доступа.Применяются примерно так:
deny from all
allow from 192.168

По умолчанию сначала выполняются все deny, потом все allow, так что allow from all разрешит доступ всем пользователям, не взирая ни на какие deny. Порядок можно изменить директивой order: order allow, deny .

deny from all отлично сочетается со вторым способом защиты страниц через CGI, именно этой директивой лучше всего прикрывать всякие пароли к гостевым книгам и т.д. При попытке обращения к страницам из этого каталога пользователь получит сообщение о несуществующей странице.

Кстати, тут между делом демонстрируется самостоятельная обработка ошибок: в данном случае - код 403, Forbidden. Аналогично обрабатывается и всеми любимая 404 - Not Found, и 401 - Unauthorized. Для этого достаточнодобавить в.htaccess директиву ErrorDocument код url :
ErrorDocument 404 /cgi-bin/bad.pl
ErrorDocument 403 /cgi-bin/badaccess.pl
ErrorDocument 401 /cgi-bin/badaccess.pl

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

Для заключительного примера используем файл.htaccess со следующим содержимым:

AuthType BasicAuthName TestAuthGroupFile /my/local/path/tgroupAuthUserFile /my/local/path/tuserrequire group test

В файле tgroup всего одна строчка - test: login test , в файле tuser - зашифрованные пароли для login (password) и test (test). Обратите внимание, при повторном обращении к этой странице браузер понимает, что только что обращался к этой области, и не утруждает пользователялишним запросом пароля.

Таков вкратце минимальный набор сведений, необходимых для защиты web-страниц. Как показывает практика, более-менее доверять стоит лишь решениям, основанным на средствах, предоставляемых сервером (и то до тех пор, пока в сервере не обнаружится очередная дырка), так что если есть возможность, лучше выбирать именно их.


Уважаемые друзья, рад снова Вас приветствовать на своем блоге « ». Сегодня речь пойдет о том, как поставить пароль на страницу сайта WordPress, здесь все очень просто, но для чего это нужно? На эти и другие вопросы я постараюсь Вам сегодня ответить.

Для чего ставить пароль на страницу

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

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

Я думаю сам принцип заработка на платном доступе понятен, поставили пароль, приняли оплату, отправили пароль доступа. Если это абонентская плата, то раз в месяц меняете пароль, опять собираете оплату и отправляете новый пароль. Все это можно автоматизировать с помощью отличного сервиса e-autopay.com , данный сервис очень удобен в плане приема платежей и автоматической рассылки электронных и физических товаров, пин-кодов и так далее, все можно настроить в плоть до удобной партнерской программы, советую обратить внимание, сервисом пользуются все известные инфобизнесмены такие как, Азамат Ушанов, Александр Борисов и многие другие. Кстати, тоже реализована на сервисе e-autopay.com .

Теперь давайте с Вами узнаем, как поставить пароль на страницу сайта WordPress. Для этого нам нужно, естественно, сначала создать нужную страницу, а затем зайти в редактирование записи и перейти к вкладке «Опубликовать» и нажать на ссылку «редактировать», смотрите рисунок.

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

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

Теперь Вы знаете как поставить пароль на страницу или статью сайта. Надеюсь данная информация принесет Вам пользу и новые идеи по заработку на своем сайте. Как всегда жду Ваших вопросов и комментариев к данной статье.

Ставим пароль на страницу

Данная статья не претендует на какие-то откровения, все эти вещи достаточно очевидны и широко известны. Но получив за последнее время несколько вопросов об ограничении доступа к 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..js"> принципиально ничего не меняют.

Уровнем повыше расположена аналогичная система, реализованная на 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 = "http://www.webclub.ru/materials/ pagepsw/ok.html"; } else { s = "http://www.webclub.ru/materials/ pagepsw/bad.html"; } try { getAppletContext().showDocument (new URL(s)); } catch(Exception e) { password.setText(e.toString()); } return true; } return false; } }

Включив этот апплет в страницу, можно получить нечто такое:

Password check

Его можно сделать поумнее, завести для каждого пользователя отдельную страницу, заставить считывать данные из файла и т.д. Принципиальный недостаток - после того как человек попал на искомую страницу, никто не в силах запретить ему запомнить этот 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);

Пример использования:

Password check

Чтобы справиться с первым недостатком, можно динамически сформировать новую страницу на основе спрятанной где-то там внутри, не выдавая при этом 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() { # Здесь заодно можно на лету модифицировать html-код # Зачем? Ну мало ли... :) print $_; } close (FL);

Пример использования:

Password check

Как видно, 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 все делается несколько иначе. Защита ставится на уровне каталогов. Соответствующие директивы могут быть помещены как в в общий конфигурационный файл (в разделе ), так и в файлы.htaccess. Набор директив в обоих случаях одинаков, а для большинства людей, арендующих место под сайт/страницу на чужом сервере, гораздо актуальнее второй способ. Итак, вы создаете в каталоге, доступ к которому планируется ограничить, файл.htaccess, после чего вставляете в него следующие директивы (привожу основные):

AuthType тип контроля - обычно используется Basic.

AuthName имя - задает имя области, в которой действительны имена и пароли пользователей. Это то самое имя, которое броузер показывает в диалоге ввода пароля. Задав одно такое имя для разных каталогов, можете сэкономить пользователям время по вводу лишнего пароля.

AuthGroupFile имя - задает имя файла, в котором хранятся имена групп и их членов. Его формат:
group1: member1 member2 ...
group2: member3 member4 ...

AuthUserFile имя - задает имя файла с паролями. По большому счету для его формирования надо воспользоваться утилитой htpasswd из поставки Apache. Но по крайней мере для некоторых версий сервера этот формат такой:
user1:passwordhash1
user2:passwordhash2

Passwordhash вполне можно получить стандартной функцией Perl"а:
$hash=crypt($pass,$salt);
где $pass - пароль, $salt - строка из двух символов, участвующая в формировании хэша.

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

require user user1 user2 и require group user1 user2 позволяют указать, какие пользователи и группы получат доступ к данному каталогу.

require valid-user разрешает доступ всем пользователям, указанным в файле паролей системы.

... , где methodi определяет HTTP-метод. Например, ограничивает применение вложенных в нее директив случаями использования методов GET и POST (обычно этого более чем достаточно). Вложенными могут быть директивы require, order, allow и deny.

Еще пара полезных директив - deny и allow - соответственно запрещения и разрешения доступа. Применяются примерно так:
deny from all
allow from 192.168

По умолчанию сначала выполняются все deny, потом все allow, так что allow from all разрешит доступ всем пользователям, невзирая ни на какие deny. Порядок можно изменить директивой order: order allow, deny.

deny from all отлично сочетается со вторым способом защиты страниц через CGI, именно этой директивой лучше всего прикрывать всякие пароли к гостевым книгам и т.д.

Кстати, тут между делом демонстрируется самостоятельная обработка ошибок: в данном случае - код 403, Forbidden. Аналогично обрабатывается и всеми любимая 404, Not Found, и 401, Unauthorized. Для этого достаточно добавить в.htaccess директиву ErrorDocument код url :
ErrorDocument 404 /cgi-bin/bad.pl
ErrorDocument 403 /cgi-bin/badaccess.pl
ErrorDocument 401 /cgi-bin/badaccess.pl

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

Для заключительного примера используем файл.htaccess со следующим содержимым:

AuthType Basic AuthName Test AuthGroupFile /.../pagepsw/deny/tgroup AuthUserFile /.../pagepsw/deny/tuser require group test

В файле tgroup всего одна строчка - test: login test , в файле tuser - зашифрованные пароли для login (password) и test (test). Обратите внимание, при повторном обращении к этой странице броузер понимает, что только что обращался к этой области, и не утруждает пользователя лишним запросом пароля.

Таков вкратце минимальный набор сведений, необходимых для защиты web-страниц. Как показывает практика, более-менее доверять стоит лишь решениям, основанным на средствах, предоставляемых сервером (и то до тех пор, пока в сервере не обнаружится очередная дырка), так что если есть возможность, лучше выбирать именно их.

Рассматриваются простые способы закрыть директорию или файлы паролем. Как авторизовывать пользователя через куки (cookies). Идентификация пользователя через встроенный в PHP4 механизм сессий.

Пароль на страницу. Часть 1. Скорее теоретическая.

я решил описать способы закрыть паролем часть сайта. Тема, на самом деле, большая, поэтому на первый раз ограничусь авторизацией php+mysql.

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

Добавлю две вещи. Первое - это куда класть файл.htpasswd. Экспериментальным путем я выяснил, что если, например, путь к документу с сообщением об ошибке (ErrorDocument) пишется относительно системной переменной DocumentRoot. Но путь к файлу с паролями (UserFile) пишется относительно ServerRoot. Насколько я понял, выше ServerRoot положить.htpasswd нельзя - "../" не воспринимается. Всё это сделано для того, чтобы можно было поместить файл с паролями, например, одним уровнем выше корневой директории сайта, чтобы из сети доступа к файлу не было вообще.

Второе - это то, что скрипт может узнать, кто его открывает и пароль: переменные $PHP_AUTH_USER и $PHP_AUTH_PW.

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

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

Автоматизация авторизации

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

Каждая страница закрытой территории подключает файл с вот таким кодом:

$result = mysql_query(" SELECT * FROM person WHERE login="". preg_replace("/[^\\w_-]/","",$PHP_AUTH_USER). "" AND pass="". md5($PHP_AUTH_PW). """); if (@mysql_num_rows($result)!=1) { header("WWW-Authenticate: Basic realm=\"User area\""); header("HTTP/1.0 401 Unauthorized"); print("Чтобы войти в пользовательскую часть сайта, надо ввести имя и пароль."); exit(); }; $user_row = mysql_fetch_array($result);

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

Конечно же, пример, который я привёл, имеет ряд существенных недостатков. Не переписывайте его один-в-один, чтобы потом не пасть жертвой попыток подбора пароля, потому что
1. защиты от подбора здесь нет
2. если таблица пользователей большая, при подборе пароля злоумышленник, скорее всего, "завалит" базу

И последний на сегодня способ - хранение зашифрованных данных в куках.

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

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

Все остальные программы подключают код, который делает следующее. Делает запрос в базу - выбирает строку с полученным логином. Из этой строки берет поле "log_time" и пароль и делает из них, как и описано выше, хэш. Сравнивает его с тем, что получил, и если они совпадают, выдает новую куку хэша, опять же, от пароля, времени и буквы "Ы" и делает запрос в базу данных "UPDATE user SET log_time="..." WHERE login="$cookie_login"".

If (isset($HTTP_COOKIE_VARS[$cookie_login]) && isset($HTTP_COOKIE_VARS[$cookie_code])) { $login = $HTTP_COOKIE_VARS[$cookie_login]; $code = $HTTP_COOKIE_VARS[$cookie_code]; $result = mysql_query("SELECT date_format(log_date,"%Y%m%d%H%i%s") as log_date1,pass,uid FROM user WHERE email="$login" AND log_date>"DATE_SUB(NOW(),INTERVAL 15 MINUTE)""); if (!mysql_error() && @mysql_num_rows($result)==1) { $log_time0 = time(); $log_time1 = date("YmdHis", $log_time0); $log_time2 = date("Y-m-d H:i:s", $log_time0); $current_user = mysql_fetch_array($result); if (md5($current_user["pass"].$current_user["log_date1"].$md5letter) == $code) { mysql_query("UPDATE user SET log_date="$log_time2" WHERE uid=".$current_user["uid"]); setcookie($cookie_code, md5($current_user["pass"].$log_time1.$md5letter), time()+900, $site_path); $auth = true; } else unset($current_user); }; };

Опять же, здесь нет никакой защиты от подбора и атаки на сервер (кстати, здесь можно вместо буквы "Ы" писать IP-адрес пользователя - чтобы, например, соседу по офису нельзя было взять файл с кукой и зайти со своего компьютера).

Пароль на страницу. Часть 2. Блокировка подбора

Когда я выложил этот выпуск в прошлый раз, меня запинали на месте, мол такой блокировкой можно и сервер "пустить под откос".

Но сначала о блокировке подбора. Банальности, но всё-таки. Пароль длинной десять символов из букв латиницы и цифр - это очень много вариантов. Если подбирать пароль по 1 000 000 вариантов в секунду, понадобится несколько тысяч лет. Но поскольку такую абракадабру запомнить сложно, мы чаще делаем пароль из осмысленных слов. Несколько лет назад оказалось, что большинство паролей можно подобрать при помощи словаря из 10 000 слов. В своё время в сети появился червь (вирус такой), который лазил по юниксовым серверам, используя их дырки в защите, и подбирал пароли привелигированых пользователей при помощи... системного орфографического словаря Юникса. Ничего таскать не надо было!

Каждый пользователь, пока он не ввёл правильный логин и пароль, считается злобным хакером. С чем же мы имеем дело, когда пользователь вводит что-либо неправильно?

  • забывчивость (на это на приличных сайтах есть формочка "забыл пароль", чтобы отправить на введёный в системных настройках email этот самый пароль)
  • баловство ("ибо нефиг")
  • подбор пароля по словарю (вероятность удачного подбора велика, поэтому закрывать надо, тем более, если сайт коммерческого характера)
  • DoS-атака (чтобы не перегрузить сервер, надо минимизировать действия, которые будет выполнять скрипт в таком случае)

    Я долго думал, как можно вызвать перегрузку на сервере, если механизм защиты стоит на файлах. Оказалось, несложно (сколько это будет стоить - другой вопрос). Итак, допустим, сервер не выдержит, если скрипт будет пытаться 1000 раз в секунду открывать файлы на запись и писать в них данные. Поскольку после 5 неудачных попыток войти в систему пользователь будет сразу получать отказ в доступе (без какой-либо записи данных в файл), надо найти 200 уникальных IP, с которых по пять раз и обратиться. Это возможно. Вешаем в баннерокрутилке html-баннер с пятью тегами:

    Пользователь моментально делает пять обращений сервер пять раз пишет в файл (кстати, в некоторых броузерах, возможно, выскочит окно для ввода логина и пароля). Можно сделать html-страницу с пятью такими картинками, а саму страницу вставить через iframe на посещаемый сайт (через iframe - чтобы по полю referer не нашли. Вряд ли служба поддержки халявного хостинга будет заниматься такими вещами как копание в лог-файлах в поисках рефереров). Те примеры, которые я привёл, разумеется, натянуты, но сам факт того, что можно воспользоваться таким недостатком системы, доказан. Кстати, нечто подобное уже было .

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

    Order deny,allow deny from all allow from xxx.xxx.xxx

    А вот код программы:

    $errors = 0; $fn = "ignore/". preg_replace("[^\d\.]", "", $REMOTE_ADDR. ".". $HTTP_FORWARDED_FOR); if (is_file($fn)) { if (filectime($fn) < time()-3600) unlink($fn); else $errors = fread(fopen($fn, "r"), 2); }; if ($errors>5) { print ("Доступ закрыт. Зайдите через час."); exit(); };

    // здесь происходит установка связи с сервером БД. чтобы не трогать зря, если пользователя сразу же "отлупили".

    $result = mysql_query("SELECT * FROM user WHERE login="". preg_replace("/[^\w_\-]/", "", $PHP_AUTH_USER). "" AND pass="". md5($PHP_AUTH_PW). """); if (@mysql_num_rows($result)!=1) { header("WWW-Authenticate: Basic realm=\"secret area\""); header("HTTP/1.0 401 Unauthorized"); print ("Authorization required"); fwrite(fopen($fn, "w"), ++$errors); exit(); }; $current_user = mysql_fetch_array($result); mysql_free_result($result);

    Впрочем, грех работать с файлами, если есть база. Шутка. Для непрошедших авторизаций создаём таблицу:

    CREATE TABLE unauth (username VARCHAR(64) NOT NULL, pass VARCHAR(64) NOT NULL, ip VARCHAR(255), logintime TIMESTAMP)

    И вместо обращения к файлам работаем с базой.

    $errors = @mysql_result(mysql_query("SELECT count(username) as falses FROM unauth WHERE logintime>DATE_SUB(NOW(),INTERVAL 1 HOUR) AND ip="$REMOTE_ADDR""),0); if (mysql_error()) die(mysql_error()); if ($errors>5) { print ("Доступ закрыт. Зайдите через час."); exit(); }; $result = mysql_query("SELECT * FROM user WHERE login="". preg_replace("/[^\w_\-]/", "", $PHP_AUTH_USER). "" AND pass="". md5($PHP_AUTH_PW). """); if (@mysql_num_rows($result)!=1) { header("WWW-Authenticate: Basic realm=\"secret area\""); header("HTTP/1.0 401 Unauthorized"); print ("Authorization required"); mysql_query("INSERT INTO unauth (username, pass, ip) VALUES ("$PHP_AUTH_USER", "$PHP_AUTH_PW", "$REMOTE_ADDR $HTTP_X_FORWARDED_FOR")"); exit(); }; $current_user = mysql_fetch_array($result); mysql_free_result($result);

    Хранить ли старые записи для статистики или нет - дело хозяйское. Если что, их можно удалять, выполняя перед авторизацией запрос:

    DELETE FROM unauth WHERE logintimeDATE_SUB(NOW(), INTERVAL 30 MINUTE)"); if (!mysql_error() && @mysql_num_rows($login_result)==1) { /* Получаем строку таблицы и формируем хэш от нужных полей. */ $current_user = mysql_fetch_array($login_result); $hash_to_check = md5($current_user["passwd"]. " Ы - чтоб никто не догадался ". $current_user); if ($hash_to_check == $HTTP_COOKIE_VARS[$COOKIE_HASH_NAME]) { $current_time = time(); /* Обновление поля последнего входа и выдача новой куки. */ mysql_query("UPDATE user SET last_log="". date("Y-m-d H:i:s", $current_time). "" WHERE login="$login""); setcookie($COOKIE_HASH_NAME, md5(date("Y-m-d H:i:s", $current_time). " Ы - чтоб никто не догадался ". $current_user["passwd"]), $current_time + 1800, $COOKIE_PATH); } else { /* В случае несовпадения хэша пользователь перенаправляется на страицу входа в систему. */ header ("Location: /login.php"); exit; }; } elseif (!mysql_error() && @mysql_num_rows($log_result)!=1) { header("Location: /login.php"); exit; } else print (mysql_error());

    Разумеется, " Ы - чтоб никто не догадался " лучше тоже выделить в отдельную переменную, а лучше использовать вместо этой строки ip-адрес посетителя (или, для обрывающегося диалапа, первые два/три числа ip-адреса).

    Кстати, насчёт IP-адреса. Его лучше проверять, но не весь адрес, а только первые два (для ip, начинающихся на число меньше 127) или три (соответственно, больше 127) числа адреса. Это спасёт пользователей плохого и обрывающегося диалапа от необходимости заново авторизовыватсья после обрыва связи, и в то же время, не даст зайти взломщику, укравшему куку. Конечно же, он не сможет перезвонить и зайти через другого провайдера - адрес пула не тот, но это не наши проблемы ("в такую погоду свои дома сидят"). Как не наша проблема и воровство паролей внутри фирмы. Мы защитили от любопытных товарищей и неграмотных взломщиков, а против троянов и снифферов, которые можно поставить жертве, ничего сделать не можем.

    На этом "навороты" закончились. Надёжнее защиту уже не сделать. Никто не будет лазить в файл кук за хэшем и подбирать его. Проще будет поместить между пользователем и веб-интерфейсом сниффер и при помощи него найти пароль. Можно поместить трояна, который будет запоминать всё, что пользователь ввёл на клавиатуре, но это уже не наши проблемы. Чтобы защититься от прослушивания канала, надо использовать соединения типа SSL или шифрование данных.

    Пароль на страницу. Часть 5. Сессии

    Зачем я писал заметку про куки? "Не понимаю, зачем писать про куки, когда в php есть сессии?!" Затем, чтобы у читателей не образовывалась перед глазами плоская картина. Не везде ещё стоит php 4-й версии, а в третьей они не поддерживаются. Более того, не везде сессии так необходимы - за редким исключением алгоритм авторизации проверяет правильность логина/пароля и правильность данных сессии, а затем либо отфутболивает клиента на страницу входа, либо берёт массив (или объект) с данными о пользователе.

    Случаев, когда работа сессиями необходима, не так уж и часты. Например, в своей игре "Монополист" я сразу стал использовать сессии, потому что пользователь может играть в нескольких играх и одна и та же страница в одном и том же сеансе работы может содержать разные данные. Там лучше данные для одной из игр, в которых пользователь участвует, хранить в сессии и сделать страницу для перехода между играми.

    В общем, я не утверждаю, что сессиями пользоваться не нужно. Нужно, только всему своё место. К вопросу применимости трёх способов авторизации - через 401-й заголовок ("realm"), куки или сессии - я вернусь позже. Сейчас поговорю о сессиях.

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

    Много про механизм сессий рассказывать не буду - уже рассказано. В самом простом виде (вернее в самом dafault-ном) механизм этот работает так: система держит на сервере файл сессии, в котором содержатся её переменные. Пользователь при запуске сессии получает уникальный идентификатор (обычно через куку), и при обращении к другим страницам отправляет её. При запуске механизма сессий в вашем скрипте обработчик php проверяет, существует ли файл соответствующий пришедшему идентификатору сессии - если существует, то скрипт сможет прочесть данные из файла, если нет - будет запущена новая сессия и создан файл. Разумеется, имя данной переменной опеределено в установках php.

    Теперь о том, какими функциями мы пользуемся.

    session_start() . Запускает сам механизм сессий. От пользователя должна быть переменная и соответствующий ей файл. Если нет файла, он создаётся, и сессия запускается с нуля. Если нет ни файла, ни переменной, то генерируется переменная (например, посылается заголовок с кукой) и создаётся файл.

    session_register(имя1, имя2, имя3...) . Указание, какие переменные запомнить в файле по окончании работы скрипта. После того как пользователь перейдёт к другой странице, можно запустить механизм сессий, и после вызова данной функции переменные будут доступны.

    session_destroy() . Удаляет файл данных сессии (при использовании кук надо удалять их вручную, выставив пустую куку: "setcookie(session_name())" ).

    session_set_cookie_params(жизнь, путь, домен) . Установка параметров куки с идентификатором сессии (по умолчанию кука выставляется на корень сервера и на 0 секунд - до закрытия браузера).

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

    Итак, имеем три файла - вход (login), проверка (auth) и выход (logout).

    // вырезка всех нежелательных символов $login = preg_replace("/[^\w_\.\-]/", "", $HTTP_POST_VARS["login"]); $pass = trim($HTTP_POST_VARS["pass"]); // проверка переменных if (strlen($login)==0 || strlen($pass)==0) $error = "Введите логин и пароль"; else { // проверка логина и пароля $user_result = mysql_query("SELECT * FROM user WHERE login="$login" AND pass="". md5($pass). """); /* если возникла ошибка в базе (например, пользователь всунул в сессию дли-и-инную переменную, которую база переваривать не захотела) или получилась не одна строка, отфутболиваем пользователя */ if (mysql_error()) die(mysql_error()); elseif (@mysql_num_rows($user_result) != 1) $error = "Неверное имя пользователя или пароль."; // если всё нормально, выбираем данные, запускаем сессию else { $user = mysql_fetch_assoc($user_result); session_set_cookie_params(1800, "/"); session_start(); // запоминаем данные о пользователе session_register("user"); // и дальше отправляем его куда-нибудь if (isset($HTTP_POST_VARS["return"])) header("Location: {$HTTP_POST_VARS["return"]}"); else header("Location: /"); exit(); }; }; /* здесь пользователь уже не прошёл авторизацию, но может отправить куку из закрытой сессии. очистим её. */ if (isset($HTTP_COOKIE_VARS)) setcookie(session_name()); // дальше рисуем форму, это неинтересно.

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

    /* убиваем переменную user, чтобы нельзя было, нарисовав форму, отправить данные в post-запросе. */ unset($user); // флаг "ошибка сессии" - если он включён, работа прекратится. $session_error = false; // если не существует куки с идентификатором сессии, поднять флаг if (!isset($HTTP_COOKIE_VARS)) $session_error = true; // если существует, запускаем механизм сессий и регистрируем переменную $user. else { session_start(); session_register("user"); /* если случайно в массиве нет логина и пароля, работа тоже прекращается ("ничего не знаем, мы вам их давали") */ if (!isset($user["login"]) || !isset($user["pass"])) $session_error = true; }; /* если пользователю до сих пор удалось геройски избежать ошибок, делается проверка через базу так же, как и на входе. */ if (!$session_error) { $check_result = mysql_query("SELECT uid FROM user WHERE login="{$user}" AND pass="{$user}""); if (mysql_error() || @mysql_num_rows($user_result) != 1) $session_error = true; }; // если была какая-то ошибка, то if ($session_error) { // уничтожаем данные сессии session_destroy(); // уничтожаем куку, если она была if (!isset($HTTP_COOKIE_VARS)) setcookie(session_name(),"","/"); /* отправляем пользователя на вход, с возможностью вернуться на запрошенный адрес */ header("Location: /login.php?return=$REQUEST_URI"); // прекращаем работу exit(); }; mysql_free_result($check_result);

    Пользователь проверен и в массиве $user - все данные о нём, можно, например, поприветствовать его по имени-отчеству:

    If(isset($HTTP_COOKIE_VARS)) { // запуск механизма сессий session_start(); // удаление файла session_destroy(); // удаление куки setcookie(session_name()); }; // выход со страницы header("Location: /login.php");

    Пара замечаний: закрываемая паролем часть в данном примере - весь сервер (например, service.firm.ru), для закрытия директории нужно исправить пути. Вместо PHPSESSID используется session_name() , чтобы можно было свободно менять имя идентификатора. Кстати, на одном физическом сервере можно делать разные имена идентификаторов сессий - достаточно в нужную часть положить файл.htaccess со строкой php_value session.name "ABRACADABRA" .




    Есть еще вопросы или что-то непонятно - добро пожаловать на наш

    Я решил описать способы закрыть паролем часть сайта. Тема, на самом деле, большая, поэтому на первый раз ограничусь авторизацией php+mysql.

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

    Добавлю две вещи. Первое - это куда класть файл.htpasswd. Экспериментальным путем я выяснил, что если, например, путь к документу с сообщением об ошибке (ErrorDocument) пишется относительно системной переменной DocumentRoot. Но путь к файлу с паролями (UserFile) пишется относительно ServerRoot. Насколько я понял, выше ServerRoot положить.htpasswd нельзя - "../" не воспринимается. Всё это сделано для того, чтобы можно было поместить файл с паролями, например, одним уровнем выше корневой директории сайта, чтобы из сети доступа к файлу не было вообще.

    Второе - это то, что скрипт может узнать, кто его открывает и пароль: переменные $PHP_AUTH_USER и $PHP_AUTH_PW.

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

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

    Автоматизация авторизации

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

    Каждая страница закрытой территории подключает файл с вот таким кодом:

    $result = mysql_query(" SELECT * FROM person WHERE login="". preg_replace("/[^w_-]/","",$PHP_AUTH_USER). "" AND pass="". md5($PHP_AUTH_PW). """); if (@mysql_num_rows($result)!=1) { header("WWW-Authenticate: Basic realm="User area""); header("HTTP/1.0 401 Unauthorized"); print("Чтобы войти в пользовательскую часть сайта, надо ввести имя и пароль."); exit(); }; $user_row = mysql_fetch_array($result);

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

    Конечно же, пример, который я привёл, имеет ряд существенных недостатков. Не переписывайте его один-в-один, чтобы потом не пасть жертвой попыток подбора пароля, потому что
    1. защиты от подбора здесь нет
    2. если таблица пользователей большая, при подборе пароля злоумышленник, скорее всего, "завалит" базу

    И последний на сегодня способ - хранение зашифрованных данных в куках.

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

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

    Все остальные программы подключают код, который делает следующее. Делает запрос в базу - выбирает строку с полученным логином. Из этой строки берет поле "log_time" и пароль и делает из них, как и описано выше, хэш. Сравнивает его с тем, что получил, и если они совпадают, выдает новую куку хэша, опять же, от пароля, времени и буквы "Ы" и делает запрос в базу данных "UPDATE user SET log_time=’…’ WHERE login=’$cookie_login’".

    if (isset($HTTP_COOKIE_VARS[$cookie_login]) && isset($HTTP_COOKIE_VARS[$cookie_code])) { $login = $HTTP_COOKIE_VARS[$cookie_login]; $code = $HTTP_COOKIE_VARS[$cookie_code]; $result = mysql_query("SELECT date_format(log_date,"%Y%m%d%H%i%s") as log_date1,pass,uid FROM user WHERE email="$login" AND log_date>"DATE_SUB(NOW(),INTERVAL 15 MINUTE)""); if (!mysql_error() && @mysql_num_rows($result)==1) { $log_time0 = time(); $log_time1 = date("YmdHis", $log_time0); $log_time2 = date("Y-m-d H:i:s", $log_time0); $current_user = mysql_fetch_array($result); if (md5($current_user["pass"].$current_user["log_date1"].$md5letter) == $code) { mysql_query("UPDATE user SET log_date="$log_time2" WHERE uid=".$current_user["uid"]); setcookie($cookie_code, md5($current_user["pass"].$log_time1.$md5letter), time()+900, $site_path); $auth = true; } else unset($current_user); }; };

    Опять же, здесь нет никакой защиты от подбора и атаки на сервер (кстати, здесь можно вместо буквы "Ы" писать IP-адрес пользователя - чтобы, например, соседу по офису нельзя было взять файл с кукой и зайти со своего компьютера).

    Пароль на страницу. Часть 2. Блокировка подбора

    Когда я выложил этот выпуск в прошлый раз, меня запинали на месте, мол такой блокировкой можно и сервер "пустить под откос".

    Но сначала о блокировке подбора. Банальности, но всё-таки. Пароль длинной десять символов из букв латиницы и цифр — это очень много вариантов. Если подбирать пароль по 1 000 000 вариантов в секунду, понадобится несколько тысяч лет. Но поскольку такую абракадабру запомнить сложно, мы чаще делаем пароль из осмысленных слов. Несколько лет назад оказалось, что большинство паролей можно подобрать при помощи словаря из 10 000 слов. В своё время в сети появился червь (вирус такой), который лазил по юниксовым серверам, используя их дырки в защите, и подбирал пароли привелигированых пользователей при помощи… системного орфографического словаря Юникса. Ничего таскать не надо было!

    Каждый пользователь, пока он не ввёл правильный логин и пароль, считается злобным хакером. С чем же мы имеем дело, когда пользователь вводит что-либо неправильно?
    забывчивость (на это на приличных сайтах есть формочка "забыл пароль", чтобы отправить на введёный в системных настройках email этот самый пароль)
    баловство ("ибо нефиг")
    подбор пароля по словарю (вероятность удачного подбора велика, поэтому закрывать надо, тем более, если сайт коммерческого характера)
    DoS-атака (чтобы не перегрузить сервер, надо минимизировать действия, которые будет выполнять скрипт в таком случае)

    Я долго думал, как можно вызвать перегрузку на сервере, если механизм защиты стоит на файлах. Оказалось, несложно (сколько это будет стоить — другой вопрос). Итак, допустим, сервер не выдержит, если скрипт будет пытаться 1000 раз в секунду открывать файлы на запись и писать в них данные. Поскольку после 5 неудачных попыток войти в систему пользователь будет сразу получать отказ в доступе (без какой-либо записи данных в файл), надо найти 200 уникальных IP, с которых по пять раз и обратиться. Это возможно. Вешаем в баннерокрутилке html-баннер с пятью тегами:

    Пользователь моментально делает пять обращений сервер пять раз пишет в файл (кстати, в некоторых броузерах, возможно, выскочит окно для ввода логина и пароля). Можно сделать html-страницу с пятью такими картинками, а саму страницу вставить через iframe на посещаемый сайт (через iframe — чтобы по полю referer не нашли. Вряд ли служба поддержки халявного хостинга будет заниматься такими вещами как копание в лог-файлах в поисках рефереров). Те примеры, которые я привёл, разумеется, натянуты, но сам факт того, что можно воспользоваться таким недостатком системы, доказан. Кстати, нечто подобное уже было.

    Но всё-таки приведу этот способ — зря писал, что ли? Его, кстати, можно без особого страха применять для ограниченного количества адресов (например, для локальной сети фирмы), положив в директорию файл.htaccess такого содержания:

    order deny,allow
    deny from all
    allow from xxx.xxx.xxx

    А вот код программы:

    $errors = 0; $fn = "ignore/". preg_replace("[^d.]", "", $REMOTE_ADDR. ".". $HTTP_FORWARDED_FOR); if (is_file($fn)) { if (filectime($fn) < time()-3600) unlink($fn); else $errors = fread(fopen($fn, "r"), 2); }; if ($errors>5) { print ("Доступ закрыт. Зайдите через час."); exit(); }; // здесь происходит установка связи с сервером БД. чтобы не трогать зря, если пользователя сразу же "отлупили". $result = mysql_query("SELECT * FROM user WHERE login="". preg_replace("/[^w_-]/", "", $PHP_AUTH_USER). "" AND pass="". md5($PHP_AUTH_PW). """); if (@mysql_num_rows($result)!=1) { header("WWW-Authenticate: Basic realm="secret area""); header("HTTP/1.0 401 Unauthorized"); print ("Authorization required"); fwrite(fopen($fn, "w"), ++$errors); exit(); }; $current_user = mysql_fetch_array($result); mysql_free_result($result); Впрочем, грех работать с файлами, если есть база. Шутка. Для непрошедших авторизаций создаём таблицу: CREATE TABLE unauth (username VARCHAR(64) NOT NULL, pass VARCHAR(64) NOT NULL, ip VARCHAR(255), logintime TIMESTAMP) И вместо обращения к файлам работаем с базой. $errors = @mysql_result(mysql_query("SELECT count(username) as falses FROM unauth WHERE logintime>DATE_SUB(NOW(),INTERVAL 1 HOUR) AND ip="$REMOTE_ADDR""),0); if (mysql_error()) die(mysql_error()); if ($errors>5) { print ("Доступ закрыт. Зайдите через час."); exit(); }; $result = mysql_query("SELECT * FROM user WHERE login="". preg_replace("/[^w_-]/", "", $PHP_AUTH_USER). "" AND pass="". md5($PHP_AUTH_PW). """); if (@mysql_num_rows($result)!=1) { header("WWW-Authenticate: Basic realm="secret area""); header("HTTP/1.0 401 Unauthorized"); print ("Authorization required"); mysql_query("INSERT INTO unauth (username, pass, ip) VALUES ("$PHP_AUTH_USER", "$PHP_AUTH_PW", "$REMOTE_ADDR $HTTP_X_FORWARDED_FOR")"); exit(); }; $current_user = mysql_fetch_array($result); mysql_free_result($result);

    Хранить ли старые записи для статистики или нет — дело хозяйское. Если что, их можно удалять, выполняя перед авторизацией запрос:

    DELETE FROM unauth WHERE logintime