HTTP Установка защиты на страницу используя MySQL и PHP. HTTP Установка защиты на страницу используя MySQL и PHP Теперь создадим основные скрипты для дальнейшей работы

HTTP Установка защиты на страницу используя MySQL и PHP. HTTP Установка защиты на страницу используя MySQL и PHP Теперь создадим основные скрипты для дальнейшей работы

07.09.2021

Возможно использовать функцию header() для отправки сообщения "Authentication Required" браузеру, заставив его показать окошко для ввода логина и пароля. Как только пользователь заполнит логин и пароль, ссылка, содержащая PHP-скрипт будет вызвана еще раз с предопределенными переменными PHP_AUTH_USER , PHP_AUTH_PW , и AUTH_TYPE , установленными в логин, пароль и тип аутентификации соответственно. Эти предопределенные переменные хранятся в массивах $_SERVER и $HTTP_SERVER_VARS . Поддерживаются оба типа: "Basic" и "Digest" (начиная с версии PHP 5.1.0). Подробнее смотрите функцию header() .

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

Пример #1 Пример Basic HTTP-аутентификации

if (!isset($_SERVER [ "PHP_AUTH_USER" ])) {
header ("WWW-Authenticate: Basic realm="My Realm"" );

echo "Текст, отправляемый в том случае,
если пользователь нажал кнопку Cancel"
;
exit;
} else {
echo
"

Hello { $_SERVER [ "PHP_AUTH_USER" ]} .

" ;
echo "

Вы ввели пароль { $_SERVER [ "PHP_AUTH_PW" ]} .

" ;
}
?>

Пример #2 Пример Digest HTTP-аутентификации

Это пример реализации простого скрипта Digest HTTP-аутентификации. За подробностями обращайтесь к » RFC 2617 .

$realm = "Запретная зона" ;

//user => password
$users = array("admin" => "mypass" , "guest" => "guest" );

if (empty($_SERVER [ "PHP_AUTH_DIGEST" ])) {
header ("HTTP/1.1 401 Unauthorized" );
header ("WWW-Authenticate: Digest realm="" . $realm .
"",qop="auth",nonce="" . uniqid (). "",opaque="" . md5 ($realm ). """ );

Die("Текст, отправляемый в том случае, если пользователь нажал кнопку Cancel" );
}

// анализируем переменную PHP_AUTH_DIGEST
if (!($data = http_digest_parse ($_SERVER [ "PHP_AUTH_DIGEST" ])) ||
!isset($users [ $data [ "username" ]]))
die("Неправильные данные!" );

// генерируем корректный ответ
$A1 = md5 ($data [ "username" ] . ":" . $realm . ":" . $users [ $data [ "username" ]]);
$A2 = md5 ($_SERVER [ "REQUEST_METHOD" ]. ":" . $data [ "uri" ]);
$valid_response = md5 ($A1 . ":" . $data [ "nonce" ]. ":" . $data [ "nc" ]. ":" . $data [ "cnonce" ]. ":" . $data [ "qop" ]. ":" . $A2 );

if ($data [ "response" ] != $valid_response )
die("Неправильные данные!" );

// ok, логин и пароль верны
echo "Вы вошли как: " . $data [ "username" ];

// функция разбора заголовка http auth
function http_digest_parse ($txt )
{
// защита от отсутствующих данных
$needed_parts = array("nonce" => 1 , "nc" => 1 , "cnonce" => 1 , "qop" => 1 , "username" => 1 , "uri" => 1 , "response" => 1 );
$data = array();
$keys = implode ("|" , array_keys ($needed_parts ));

Preg_match_all ("@(" . $keys . ")=(?:([\""])([^\2]+?)\2|([^\s,]+))@" , $txt , $matches , PREG_SET_ORDER );

Foreach ($matches as $m ) {
$data [ $m [ 1 ]] = $m [ 3 ] ? $m [ 3 ] : $m [ 4 ];
unset($needed_parts [ $m [ 1 ]]);
}

Return $needed_parts ? false : $data ;
}
?>

Замечание : Замечание касательно совместимости

Будьте особенно внимательны при указании HTTP-заголовков. Для того, чтобы гарантировать максимальную совместимость с наибольшим количеством различных клиентов, слово "Basic" должно быть написано с большой буквы "B", регион (realm) должен быть взят в двойные (не одинарные!) кавычки, и ровно один пробел должен предшествовать коду 401 в заголовке HTTP/1.0 401 . Параметры аутентификации должны разделяться запятыми, как это было показано в примере Digest аутентификации выше.

Вместо простого отображения на экране переменных PHP_AUTH_USER и PHP_AUTH_PW , вам, возможно, понадобится проверить их корректность. Используйте для этого запрос к базе данных или поиск пользователя в dbm-файле.

Вы можете пронаблюдать особенности работы браузера Internet Explorer. Он очень требователен к параметру передаваемых заголовков. Трюк с указанием заголовка WWW-Authenticate перед отправкой статуса HTTP/1.0 401 пока что работает для него.

Для того, чтобы предотвратить написание кем-либо скрипта, раскрывающего пароль к странице, которая использует внешнюю аутентификацию, переменные PHP_AUTH не устанавливаются в случае, если данная страница использует внешнюю аутентификацию и установлен безопасный режим . Несмотря на это, переменная REMOTE_USER может использоваться для аутентификации пользователя, прошедшего внешнюю аутентификацию. Таким образом, вы всегда можете воспользоваться переменной $_SERVER["REMOTE_USER"] .

Замечание : Замечание касательно конфигурации

PHP использует указание директивы AuthType для указания того, используется внешняя аутентификация или нет.

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

И Netscape Navigator и Internet Explorer очищают кэш аутентификации текущего окна для заданного региона (realm) при получении от сервера статуса 401. Это может использоваться для реализации принудительного выхода пользователя и повторного отображения диалогового окна для ввода имени пользователя и пароля. Некоторые разработчики используют это для ограничения авторизации по времени или для предоставления кнопки "Выход".

Пример #3 Пример HTTP-аутентификации с принудительным вводом новой пары логин/пароль

function authenticate () {
header ("WWW-Authenticate: Basic realm="Test Authentication System"" );
header ("HTTP/1.0 401 Unauthorized" );
echo "Вы должны ввести корректный логин и пароль для получения доступа к ресурсу \n" ;
exit;
}

if (!isset($_SERVER [ "PHP_AUTH_USER" ]) ||
($_POST [ "SeenBefore" ] == 1 && $_POST [ "OldAuth" ] == $_SERVER [ "PHP_AUTH_USER" ])) {
authenticate ();
} else {
echo "

Добро пожаловать: " . htmlspecialchars ($_SERVER [ "PHP_AUTH_USER" ]) . "
" ;
echo "Предыдущий логин: " . htmlspecialchars ($_REQUEST [ "OldAuth" ]);
echo "

\n" ;
echo "\n" ;
echo ". htmlspecialchars ($_SERVER [ "PHP_AUTH_USER" ]) . "\" />\n" ;
echo "\n" ;
echo "

\n" ;
}
?>

Это поведение не регламентируется стандартами HTTP Basic -аутентификации, следовательно, вы не должны зависеть от этого. Тестирование браузера Lynx показало, что Lynx не очищает кэш авторизации при получении от сервера статуса 401, и, нажав последовательно "Back", а затем "Forward" возможно открыть такую страницу, при условии, что требуемые атрибуты авторизации не изменились. Однако, пользователь может нажать клавишу "_" для очистки кеша аутентификации.

Для того, чтобы добиться корректной работы HTTP-аутентификации в IIS сервере с CGI версией PHP, вы должны отредактировать конфигурационную настройку IIS под названием "Directory Security ". Щелкните на надписи "Edit " и установите опцию "Anonymous Access ", все остальные поля должны остаться неотмеченными.

Замечание : Замечание касательно IIS:
Для того, чтобы HTTP-аутентификация корректно работала в IIS, в конфигурации PHP опция cgi.rfc2616_headers должна быть установлена значением 0 (значение по умолчанию).

Замечание :

В случае, если используется безопасный режим , UID текущего скрипта будет добавлен в realm -часть заголовка WWW-Authenticate .

Будем учиться делать простую аутентификацию пользователей на сайте. На сайте могут быть страницы только для авторизованных пользователей и они будут полноценно функционировать, если добавить к ним наш блок аутентификации. Чтобы его создать, нужна база данных MySQL. Она может иметь 5 колонок (минимум), а может и больше, если вы хотите добавить информацию о пользователях. Назовём базу данных “Userauth”.

Создадим в ней следующие поля: ID для подсчёта числа пользователей, UID для уникального идентификационного номера пользователя, Username для имени пользователя, Email для адреса его электронной почты и Password для пароля. Вы можете использовать для авторизации пользователя и уже имеющуюся у Вас базу данных, только, как и в случае с новой базой данных, создайте в ней следующую таблицу.

Код MySQL

CREATE TABLE `users` (`ID` int (11) NOT NULL AUTO_INCREMENT, `UID` int (11) NOT NULL, `Username` text NOT NULL, `Email` text NOT NULL, `Password` text NOT NULL, PRIMARY KEY (`ID`)) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;

Теперь создадим файл "sql.php". Он отвечает за подключение к базе данных. Данный код, во первых, создаёт переменные для сервера и пользователя, когда он подключается к серверу. Во-вторых, он выберет базу данных, в данном случае "USERAUTH". Этот файл нужно подключить в "log.php" и "reg.php" для доступа к базе данных.

Код PHP

//Ваше имя пользователя MySQL $pass = "redere"; //пароль $conn = mysql_connect ($server, $user, $pass);//соединение с сервером $db = mysql_select_db ("userauth", $conn);//выбор базы данных if (!$db) { //если не может выбрать базу данных echo "Извините, ошибка:(/>";//Показывает сообщение об ошибке exit (); //Позволяет работать остальным скриптам PHP } ?>

Далее страница входа, пусть она называется "login.php". Во-первых, она проверяет введённые данные на наличие ошибок. Страница имеет поля для имени пользователя, пароля, кнопку отправки и ссылку для регистрации. Когда пользователь нажмёт кнопку «Вход», форма будет обработана кодом из файла "log.php", а затем произойдёт вход в систему.

Код PHP

0) { //если есть ошибки сессии $err = "

"; //Start a table foreach ($_SESSION["ERRMSG"] as $msg) {//распознавание каждой ошибки $err .= ""; //запись её в переменную } $err .= "
" . $msg . "
"; //закрытие таблицы unset ($_SESSION["ERRMSG"]); //удаление сессии } ?> Форма входа
Имя пользователя
Пароль
Регистрация

Затем пишем скрипт для входа в систему. Назовём его "log.php". Он имеет функцию для очистки входных данных от SQL-инъекций, которые могут испортить ваш скрипт. Во-вторых, он получает данные формы и проверяет их на правильность. Если входные данные правильны, скрипт отправляет пользователя на страницу авторизованных пользователей, если нет – устанавливает ошибки и отправляет пользователя на страницу входа.

Код PHP

//начало сессии для записи function Fix($str) { //очистка полей $str = trim($str); if (get_magic_quotes_gpc()) { $str = stripslashes ($str); } //массив для сохранения ошибок $errflag = false ; //флаг ошибки $username = Fix($_POST["username"]);//имя пользователя $password = Fix($_POST["password"]);//пароль } //проверка пароля if ($password == "") { $errmsg = "Password missing"; //ошибка $errflag = true ; //поднимает флаг в случае ошибки } //если флаг ошибки поднят, направляет обратно к форме регистрации //записывает ошибки session_write_close(); //закрытие сессии //перенаправление exit (); } //запрос к базе данных $qry = "SELECT * FROM `users` WHERE `Username` = "$username" AND `Password` = "" . md5 ($password) . """; $result = mysql_query ($qry); //проверка, был ли запрос успешным (есть ли данные по нему) if (mysql_num_rows ($result) == 1) { while ($row = mysql_fetch_assoc ($result)) { $_SESSION["UID"] = $row["UID"];//получение UID из базы данных и помещение его в сессию $_SESSION["USERNAME"] = $username;//устанавливает, совпадает ли имя пользователя с сессионным session_write_close(); //закрытие сессии header("location: member.php");//перенаправление } } else { $_SESSION["ERRMSG"] = "Invalid username or password"; //ошибка session_write_close(); //закрытие сессии header("location: login.php"); //перенаправление exit (); } ?>

Сделаем страницу регистрации, назовём её "register.php". Она похожа на страницу входа, только имеет на несколько полей больше, а вместо ссылки на регистрацию – ссылку на login.php на случай, если у пользователя уже есть аккаунт.

Код PHP

0) { //если есть ошибки сессии $err = "

"; //начало таблицы foreach ($_SESSION["ERRMSG"] as $msg) {//устанавливает каждую ошибку $err .= ""; //записывает их в переменную } $err .= "
" . $msg . "
"; //конец таблицы unset ($_SESSION["ERRMSG"]); //уничтожает сессию } ?> Форма регистрации
Имя пользователя
E-mail
Пароль
Повтор пароля
У меня есть аккаунт

Теперь сделаем скрипт регистрации в файле "reg.php". В него будет включён "sql.php" для подключения к к базе данных. Используется и та же функция, что и в скрипте входа для очистки поля ввода. Устанавливаются переменные для возможных ошибок. Далее – функция для создания уникального идентификатора, который никогда ранее не предоставлялся. Затем извлекаются данные из формы регистрации и проверяются. Происходит проверка, что адрес электронной почты указан в нужном формате, а также, правильно ли повторно указан пароль. Затем скрипт проверяет, нет ли в базе данных пользователя с таким же именем, и, если есть, сообщает об ошибке. И, наконец, код добавляет пользователя в базу данных.

Код PHP

//начало сессии для записи function Fix($str) { //очистка полей $str = @trim($str); if (get_magic_quotes_gpc()) { $str = stripslashes ($str); } return mysql_real_escape_string ($str); } $errmsg = array (); //массив для хранения ошибок $errflag = false ; //флаг ошибки $UID = "12323543534523453451465685454";//уникальный ID $username = Fix($_POST["username"]);//имя пользователя $email = $_POST["email"]; //Email $password = Fix($_POST["password"]);//пароль $rpassword = Fix($_POST["rpassword"]);//повтор пароля //проверка имени пользователя if ($username == "") { $errmsg = "Username missing"; //ошибка $errflag = true ; //поднимает флаг в случае ошибки } //проверка Email if(!eregi("^[_a-z0-9-]+(\.[_a-z0-9-]+)*@+(\.+)*(\.{2,3})$", $email)) { //должен соответствовать формату: [email protected] $errmsg = "Invalid Email"; //ошибка $errflag = true ; //поднимает флаг в случае ошибки } //проверка пароля if ($password == "") { $errmsg = "Password missing"; //ошибка $errflag = true ; //поднимает флаг в случае ошибки } //проверка повтора пароля if ($rpassword == "") { $errmsg = "Repeated password missing";//ошибка $errflag = true ; //поднимает флаг в случае ошибки } //проверка валидности пароля if (strcmp($password, $rpassword) != 0) { $errmsg = "Passwords do not match";//ошибка $errflag = true ; //поднимает флаг в случае ошибки } //проверка, свободно ли имя пользователя if ($username != "") { $qry = "SELECT * FROM `users` WHERE `Username` = "$username""; //запрос к MySQL $result = mysql_query ($qry); if ($result) { if (mysql_num_rows ($result) > 0) {//если имя уже используется $errmsg = "Username already in use"; //сообщение об ошибке $errflag = true; //поднимает флаг в случае ошибки } mysql_free_result ($result); } } //если данные не прошли валидацию, направляет обратно к форме регистрации if ($errflag) { $_SESSION["ERRMSG"] = $errmsg; //сообщение об ошибке session_write_close(); //закрытие сессии header("location: register.php");//перенаправление exit (); } //добавление данных в базу $qry = "INSERT INTO `userauth`.`users`(`UID`, `Username`, `Email`, `Password`) VALUES("$UID","$username","$email","" . md5 ($password) . "")"; $result = mysql_query ($qry); //проверка, был ли успешным запрос на добавление if ($result) { echo "Благодарим Вас за регистрацию, " .$username . ". Пожалуйста, входите сюда"; exit (); } else { die ("Ошибка, обратитесь позже"); } ?>

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

Код PHP

И, наконец, скрипт "auth.php" можно использовать, чтобы сделать страницы доступными только для авторизованных пользователей. Он проверяет данные входа и, если они верны, позволяет пользователю просматривать страницы, а если нет, просит авторизоваться. Кроме того, если кто-то попытается взломать сайт создав одну из сессий, она будет прервана, как в общем случае.

Код PHP

Одно из условий в коде выше является предметом вопроса в .

Следующий код нужно вставить на страницу для авторизованных пользователей, она называется, например, "member.php", а у Вас может называться как угодно.

Код PHP

Вам разрешён доступ к этой странице. Выйти ( )

Аутентификация пользователей готова!

Для того, чтобы отправить браузеру клиента сообщение "Authentication Required", что в свою очередь приведет к появлению диалогового окна для ввода имени пользователя и пароля. После того как клиент ввел свое имя и пароль, скрипт будет вызван повторно, но уже с предопределенными переменными PHP_AUTH_USER , PHP_AUTH_PW и AUTH_TYPE , которые соответственно содержат имя пользователя, пароль и тип аутентификации. Эти переменные могут быть найдены в массиве $_SERVER и $HTTP_SERVER_VARS . В настоящее время поддерживается только "Basic"-аутентификация. Также вы можете ознакомится с более детальным описанием функции header() .

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

Пример HTTP-аутентификации

if (!isset($_SERVER [ "PHP_AUTH_USER" ])) {
header ("WWW-Authenticate: Basic realm="My Realm"" );

echo "Текст, отправляемый в том случае,
если пользователь нажал кнопку Cancel"
;
exit;
} else {
echo
"

Hello {$_SERVER["PHP_AUTH_USER"]}.

"
;
echo "

Вы ввели пароль {$_SERVER["PHP_AUTH_PW"]}.

"
;
}
?>

Примечание касательно совместимости: Будьте особенно внимательны при указании HTTP-заголовков. Для того, чтобы гарантировать максимальную совместимость с наибольшим количеством различных клиентов, слово "Basic" должно быть написано с большой буквы "B", регион (realm) должен быть взят в двойный (не одинарные!) кавычки, и ровно один пробел должен предшествовать коду 401 в заголовке HTTP/1.0 401 .

Вместо простого отображения на экране переменных PHP_AUTH_USER и PHP_AUTH_PW , вам, возможно, понадобится проверить их корректность. Используйте для этого запрос к базе данных или поиск пользователя в dbm-файле.

Вы можете пронаблюдать особенности работы браузера Internet Explorer. Он очень требователен к параметру передаваемых заголовков. Указание заголовка WWW-Authenticate перед отправкой статуса HTTP/1.0 401 является небольшой хитростью.

Начиная с PHP 4.3.0, для того, чтобы предотвратить написание кем-либо скрипта, раскрывающего пароль к странице, которая использует внешнюю аутентификацию, переменные PHP_AUTH не устанавливаются в случае, если данная страница использует внешнюю аутентификацию и установлен безопасный режим . Несмотря на это, переменная REMOTE_USER может использоваться для аутентификации пользователя, прошедшего внешнюю аутентификацию. Таким образом, вы всегда можете воспользоваться переменной $_SERVER["REMOTE_USER"] .

Примечание: PHP использует указание директивы AuthType для указания того, используется внешняя аутентификация или нет.

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

И Netscape Navigator и Internet Explorer очищают кеш аутентификации текущего окна для заданного региона (realm) при получении от сервера. Это может использоваться для реализации принудительного выхода пользователя и повторного отображения диалогового окна для ввода имени пользователя и пароля. Некоторые разработчики используют это для ограничения авторизации по времени или для предоставления кнопки "Выход".

Пример HTTP-аутентификации с принудительным вводом новой пары логин/пароль

function authenticate () {
header ("WWW-Authenticate: Basic realm="Test Authentication System"" );
header ("HTTP/1.0 401 Unauthorized" );
echo "Вы должны ввести корректный логин и пароль для получения доступа к ресурсу \n" ;
exit;
}

If (!isset($_SERVER [ "PHP_AUTH_USER" ]) ||
($_POST [ "SeenBefore" ] == 1 && $_POST [ "OldAuth" ] == $_SERVER [ "PHP_AUTH_USER" ])) {
authenticate ();
}
else {
echo
"

Добро пожаловать: {$_SERVER["PHP_AUTH_USER"]}
" ;
echo "Предыдущий логин: {$_REQUEST["OldAuth"]}" ;
echo "

\n" ;
echo "\n" ;
echo "\n" ;
echo "\n" ;
echo "

\n" ;
}
?>

Это поведение не регламентируется стандартами HTTP Basic-аутентификации, следовательно, вы не должны зависеть от этого. Как показали тесты, браузер Lynx не очищает кеш авторизации при получении от сервера статуса 401, и, нажав последовательно "Back", а затем "Forward" возможно открыть такую страницу, при условии, что требуемые атрибуты авториазации не изменились. Однако, пользователь может нажать клавишу "_" для очистки кеша аутентификации.

Также следует заметить, что до версии PHP 4.3.3, HTTP-аутентификация не работала на серверах под управлением Microsoft IIS, если PHP был установлен как CGI-модуль, в силу некоторых ограничений IIS. Для того, чтобы добиться корректной работы в PHP 4.3.3+, вы должны отредактировать конфигурационную настройку IIS под названием "Directory Security". Щелкните на надписи "Edit" и установите опцию "Anonymous Access", все остальные поля должны остаться неотмеченными.

Еще одно ограничение, если вы используете IIS посредством ISAPI: переменные PHP_AUTH_* не определены, но в то же время доступна переменная HTTP_AUTHORIZATION . Пример кода, который вы могли бы использовать: list($user, $pw) = explode(":", base64_decode(substr($_SERVER["HTTP_AUTHORIZATION"], 6)));

Примечание касательно IIS:: Для того, чтобы HTTP-аутентификация корректно работала в IIS, в конфигурации PHP опция cgi.rfc2616_headers должна быть установлена значением 0 (значение по умолчанию).

Внимание: В случае, если используется защищенный режим , UID текущего скрипта будет добавлен в realm -часть заголовка WWW-Authenticate .



<<< Назад Содержание Вперед >>>
Есть еще вопросы или что-то непонятно - добро пожаловать на наш

Эта статья устарела.

Эта статья написана для услуги Виртуальный хостинг, которая считается устаревшей с 1 июня 2019 года.

Актуальную услугу хостинга можно заказать на нашем сайте

HTTP-авторизация средствами PHP

В данной статье рассмотрено создание HTTP-авторизации с помощью PHP, что позволит закрыть какой-либо раздел сайта, например административную часть.

Для установления подлинности HTTP обеспечивает простой механизм "вызов-ответ" (challenge-response), который может использоваться сервером для вызова (challenge) клиентского запроса, а клиентом для предоставления опознавательной информации (authentication information). Наиболее распространенной схемой авторизации является "Базовая схема установления подлинности" (Basic Authentication Scheme).

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

После получения запроса на идентификацию, сервер отвечает вызовом (challenge), подобным следующему:

WWW-Authenticate: Basic realm="Restricted Area" HTTP/1.1 401 Unauthorized

Здесь "Restricted Area" -- строка, назначенная сервером, которая идентифицирует защищенную область запрашиваемого URI (Request-URI). Говоря простым языком -- имя защищенной области.

Далее, чтобы получить права доступа, агент пользователя (браузер) отправляет на сервер идентификатор пользователя (имя пользователя) и пароль, разделенные одним символом двоеточия (":"), внутри base64-кодированной строки рекомендаций (credentials):

Basic-credentials = "Basic" basic-cookie

Здесь

  • basic-cookie -- base64-кодированая строка, содержащая user-pass
  • user-pass -- строка вида "userid:password"
  • userid -- текст, не содержащий символов ":"
  • password -- текст

Обратите внимание, что и имя пользователя и пароль являются чувствительными к регистру. То есть, например, User и user -- два различных имени пользователя.

HTTP-авторизация и PHP

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

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

RewriteCond %{HTTP:Authorization} ^Basic.* RewriteRule (.*) index.php?authorization=%{HTTP:Authorization}

При запросе через HTTP к файлу sitename.ru/www/index.php, данное правило будет передавать GET-запросом содержимое непустого поля Authorization в параметр authorization. Если мы средствами PHP посмотрим на содержимое переменной $_GET["authorization"], то увидем как раз описываемый выше basic-credentials -- строку вида:

Preg_match("/^Basic\s+(.*)$/i", $_GET["authorization"], $user_pass); list($user,$pass)=explode(":",base64_decode($user_pass));

Таким образом мы получим две переменные -- $user и $pass, содержащие соответствено имя пользователя и пароль. Теперь, как упоминалось выше, их нужно лишь каким-либо образом обработать -- например, сравнить с аналогичными переменными из базы данных или из файла с учетными записями пользователей.

Заключение

Рассмотренный в данной статье метод будет успешно работать не только на нашем хостинге, но и везде, где PHP работает в режиме CGI/FastCGI и в качестве веб-сервера используется Apache + mod_rewrite.

Исходные тексты рабочих примеров вы можете найти в Приложении к данной статье.

Приложение. Исходные тексты скрипта

Исходный текст файла.htaccess

RewriteEngine on RewriteBase / RewriteCond %{HTTP:Authorization} ^Basic.* RewriteRule (.*) index.php?authorization=%{HTTP:Authorization}

Исходный текст PHP-скрипта

$authenticated=0; if(isset($_GET["authorization"])) { if(preg_match("/^Basic\s+(.*)$/i", $_GET["authorization"], $user_pass)) { list($user,$pass)=explode(":",base64_decode($user_pass)); // Проверка корректности введенных реквизитов доступа if($user=="user" && $pass=="password") { $authenticated=1; } } } if($authenticated) { // Авторизация успешно пройдена echo("user: ".$user."
pass: ".$pass); } else { header("WWW-Authenticate: Basic realm="Restricted Area""); header("HTTP/1.1 401 Unauthorized"); echo("Access denied."); }

Возможно использовать функцию header() для посылки сообщения "Authentication Required" браузеру, заставив его показать окошко для ввода логина и пароля. Как только пользователь заполнит логин и пароль, ссылка, содержащая PHP-скрипт будет вызвана еще раз с предопределенными переменными PHP_AUTH_USER , PHP_AUTH_PW , и AUTH_TYPE , установленными в логин, пароль и тип аутентификации соответственно. Эти предопределенные переменные хранятся в массивах $_SERVER и $HTTP_SERVER_VARS . Поддерживаются оба типа: "Basic" и "Digest" (начиная с версии PHP 5.1.0). Подробнее смотрите функцию header() .

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

Пример #6 Пример Basic HTTP-аутентификации

if (!isset($_SERVER [ "PHP_AUTH_USER" ])) {
header ("WWW-Authenticate: Basic realm="My Realm"" );

echo "Текст, отправляемый в том случае,
если пользователь нажал кнопку Cancel"
;
exit;
} else {
echo
"

Hello { $_SERVER [ "PHP_AUTH_USER" ]} .

" ;
echo "

Вы ввели пароль { $_SERVER [ "PHP_AUTH_PW" ]} .

" ;
}
?>

Пример #7 Пример Digest HTTP-аутентификации

Это пример реализации простого скрипта Digest HTTP-аутентификации. За подробностями обращайтесь к » RFC 2617 .

$realm = "Запретная зона" ;

//user => password
$users = array("admin" => "mypass" , "guest" => "guest" );

if (empty($_SERVER [ "PHP_AUTH_DIGEST" ])) {
header ("HTTP/1.1 401 Unauthorized" );
header ("WWW-Authenticate: Digest realm="" . $realm .
"",qop="auth",nonce="" . uniqid (). "",opaque="" . md5 ($realm ). """ );

Die("Текст, посылаемый, если пользователь нажал Cancel" );
}

// анализируем переменную PHP_AUTH_DIGEST
if (!($data = http_digest_parse ($_SERVER [ "PHP_AUTH_DIGEST" ])) ||
!isset($users [ $data [ "username" ]]))
die("Неправильные данные!" );

// генерируем корректный ответ
$A1 = md5 ($data [ "username" ] . ":" . $realm . ":" . $users [ $data [ "username" ]]);
$A2 = md5 ($_SERVER [ "REQUEST_METHOD" ]. ":" . $data [ "uri" ]);
$valid_response = md5 ($A1 . ":" . $data [ "nonce" ]. ":" . $data [ "nc" ]. ":" . $data [ "cnonce" ]. ":" . $data [ "qop" ]. ":" . $A2 );

if ($data [ "response" ] != $valid_response )
die("Неправильные данные!" );

// ok, логин и пароль верны
echo "Вы вошли как: " . $data [ "username" ];

// функция разбора заголовка http auth
function http_digest_parse ($txt )
{
// защита от отсутствующих данных
$needed_parts = array("nonce" => 1 , "nc" => 1 , "cnonce" => 1 , "qop" => 1 , "username" => 1 , "uri" => 1 , "response" => 1 );
$data = array();
$keys = implode ("|" , array_keys ($needed_parts ));

Preg_match_all ("@(" . $keys . ")=(?:([\""])([^\2]+?)\2|([^\s,]+))@" , $txt , $matches , PREG_SET_ORDER );

Foreach ($matches as $m ) {
$data [ $m [ 1 ]] = $m [ 3 ] ? $m [ 3 ] : $m [ 4 ];
unset($needed_parts [ $m [ 1 ]]);
}

Return $needed_parts ? false : $data ;
}
?>

Замечание : Замечание касательно совместимости

Будьте особенно внимательны при указании HTTP-заголовков. Для того, чтобы гарантировать максимальную совместимость с наибольшим количеством различных клиентов, слово "Basic" должно быть написано с большой буквы "B", регион (realm) должен быть взят в двойные (не одинарные!) кавычки, и ровно один пробел должен предшествовать коду 401 в заголовке HTTP/1.0 401 . Параметры аутентификации должны разделяться запятыми, как это было показано в примере Digest аутентификации выше.

Вместо простого отображения на экране переменных PHP_AUTH_USER и PHP_AUTH_PW , вам, возможно, понадобится проверить их корректность. Используйте для этого запрос к базе данных или поиск пользователя в dbm-файле.

Вы можете пронаблюдать особенности работы браузера Internet Explorer. Он очень требователен к параметру передаваемых заголовков. Трюк с указанием заголовка WWW-Authenticate перед отправкой статуса HTTP/1.0 401 пока что работает для него.

Начиная с PHP 4.3.0, для того, чтобы предотвратить написание кем-либо скрипта, раскрывающего пароль к странице, которая использует внешнюю аутентификацию, переменные PHP_AUTH не устанавливаются в случае, если данная страница использует внешнюю аутентификацию и установлен безопасный режим . Несмотря на это, переменная REMOTE_USER может использоваться для аутентификации пользователя, прошедшего внешнюю аутентификацию. Таким образом, вы всегда можете воспользоваться переменной $_SERVER["REMOTE_USER"] .

Замечание : Замечание касательно конфигурации

PHP использует указание директивы AuthType для указания того, используется внешняя аутентификация или нет.

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

И Netscape Navigator и Internet Explorer очищают кэш аутентификации текущего окна для заданного региона (realm) при получении от сервера. Это может использоваться для реализации принудительного выхода пользователя и повторного отображения диалогового окна для ввода имени пользователя и пароля. Некоторые разработчики используют это для ограничения авторизации по времени или для предоставления кнопки "Выход".

Пример #8 Пример HTTP-аутентификации с принудительным вводом новой пары логин/пароль

function authenticate () {
header ("WWW-Authenticate: Basic realm="Test Authentication System"" );
header ("HTTP/1.0 401 Unauthorized" );
echo "Вы должны ввести корректный логин и пароль для получения доступа к ресурсу \n" ;
exit;
}

if (!isset($_SERVER [ "PHP_AUTH_USER" ]) ||
($_POST [ "SeenBefore" ] == 1 && $_POST [ "OldAuth" ] == $_SERVER [ "PHP_AUTH_USER" ])) {
authenticate ();
} else {
echo "

Добро пожаловать: " . htmlspecialchars ($_SERVER [ "PHP_AUTH_USER" ]) . "
" ;
echo "Предыдущий логин: " . htmlspecialchars ($_REQUEST [ "OldAuth" ]);
echo "

\n" ;
echo "\n" ;
echo ". htmlspecialchars ($_SERVER [ "PHP_AUTH_USER" ]) . "\" />\n" ;
echo "\n" ;
echo "

\n" ;
}
?>

Это поведение не регламентируется стандартами HTTP Basic -аутентификации, следовательно, вы не должны зависеть от этого. Тестирование браузера Lynx показало, что Lynx не очищает кэш авторизации при получении от сервера статуса 401, и, нажав последовательно "Back", а затем "Forward" возможно открыть такую страницу, при условии, что требуемые атрибуты авторизации не изменились. Однако, пользователь может нажать клавишу "_" для очистки кеша аутентификации.

Также следует заметить, что до версии PHP 4.3.3, HTTP-аутентификация не работала на серверах под управлением Microsoft IIS, если PHP был установлен как CGI-модуль, в силу некоторых ограничений IIS. Для того, чтобы добиться корректной работы в PHP 4.3.3+, вы должны отредактировать конфигурационную настройку IIS под названием "Directory Security ". Щелкните на надписи "Edit " и установите опцию "Anonymous Access ", все остальные поля должны остаться неотмеченными.

Еще одно ограничение, если вы используете IIS посредством ISAPI и PHP 4: переменные PHP_AUTH_* не определены, но в то же время доступна переменная HTTP_AUTHORIZATION . Пример кода, который вы могли бы использовать: list($user, $pw) = explode(":", base64_decode(substr($_SERVER["HTTP_AUTHORIZATION"], 6)));

Замечание : Замечание касательно IIS:
Для того, чтобы HTTP-аутентификация корректно работала в IIS, в конфигурации PHP опция cgi.rfc2616_headers должна быть установлена значением 0 (значение по умолчанию).

Замечание :

В случае, если используется безопасный режим , UID текущего скрипта будет добавлен в realm -часть заголовка WWW-Authenticate .

© 2024 hecc.ru - Новости компьютерных технологий