|
|
|
| Стремясь разобраться в реализации механизма авторизации пользователя, я задался следующим вопросом: допустим у меня есть страница где пользователь вводит свой логин и пароль и страница page, так вот как проверить (если пользователь вдруг напрямую ввел адрес страницы page) залогинен он или нет, и неотобразить страницу в случае, если пользователь не залогинен. Где про это можно прочитать? какие механизмы использовать? подскажите пожалуйста. | |
|
|
|
|
|
|
|
для: Alexhoppus
(10.08.2009 в 16:58)
| | На этом сайте представлена рубрика Учебник PHP, посмотрите главу Сессии и cookies в PHP. Там все подробно расписано | |
|
|
|
|
|
|
|
для: Chupach1979
(10.08.2009 в 17:00)
| | спасибо! | |
|
|
|
|
|
|
|
для: Chupach1979
(10.08.2009 в 17:00)
| | Вот именно рассмотренная там методика как раз и не спасет от ввода прямого URL с указанием чужого идентификатора сессии. | |
|
|
|
|
|
|
|
для: Trianon
(10.08.2009 в 17:26)
| | Вы всегда говорите загадками.... хоть бы раз рассказали методику. Нам не вопрос реализовать, знать бы то, что знаете вы. | |
|
|
|
|
|
|
|
для: Рома
(10.08.2009 в 23:52)
| | Я хоть раз здесь скрывал что-то, что знаю сам? | |
|
|
|
|
|
|
|
для: Trianon
(10.08.2009 в 23:58)
| | Вы заставляете людей думать вашими мыслями. | |
|
|
|
|
|
|
|
для: Рома
(11.08.2009 в 00:07)
| | Точнее. Я заставляю здешних посетителей думать. Это верно.
Потому что количество мозговых лентяев среди тех, кто так или иначе вовлечен в разработку того, что мы называем всемирной паутиной, развелось сверх всякой меры.
И если хотя бы здесь хотя бы сегодня их число уменьшится, я сочту сегодняшний день прожитым не зря.
Впрочем, это половина мотива. | |
|
|
|
|
|
|
|
для: Trianon
(11.08.2009 в 00:11)
| | я читал в книжке "не смейтесь над человеком который плохо играет в шахматы, возможно он прекрасно владеет шпагой"
люди учатся, даже задавать вопросы тоже учатся. и называть их лентяями из за это неэтично. | |
|
|
|
|
|
|
|
для: easywind
(13.08.2009 в 23:37)
| | Trianon, по моему мнению, отвечает вполне адекватно, как на вопросы полнейших новичков, так и на вопросы более продвинутых собратьев. | |
|
|
|
|
|
|
|
для: Саня
(13.08.2009 в 23:41)
| | . | |
|
|
|
|
|
|
|
для: easywind
(13.08.2009 в 23:37)
| | >я читал в книжке "не смейтесь над человеком который плохо играет в шахматы, возможно он прекрасно владеет шпагой"
>люди учатся, даже задавать вопросы тоже учатся. и называть их лентяями из за это неэтично.
Тех, что учатся, я и не называю. :)
Но уж коль скоро Вы предстали в роли Ethical Engineer'а, соблаговолите, пожалуйста, ответить: Насколько, по-Вашему, этично выносить на сервер грязный код, заведомо зная, что на сайт зайдет не один посетитель? | |
|
|
|
|
|
|
|
для: Trianon
(10.08.2009 в 23:58)
| | Предлагаете читать все ваши посты? | |
|
|
|
|
|
|
|
для: Рома
(11.08.2009 в 17:59)
| | тонкий намёк на вторую половину мотива ;) | |
|
|
|
|
|
|
|
для: Рома
(11.08.2009 в 17:59)
| | Предлагаю ответить на вопросы.
Если есть что ответить - значит есть понимание, и мои советы вроде как не нужны.
Если совсем нечего - пожалуй, читать посты пользы особой не принесет.
Да , в вопросе я опечатался, два раза спросив про один и тот же файл.
конечно, второй вопрос был про script.php . Сейчас исправил. | |
|
|
|
|
|
|
|
для: Trianon
(10.08.2009 в 17:26)
| | Вот что я написал, вроде бы работает, но уверен, что тут много чего нехорошего подсажите, что изменить, как лучше не делать, может это вообще не годится, но по крайней мере принцип я понял.
=========== index.php ==============
<?
print "<form action=\"\authorize.php\" method=\"POST\">\n";
print "<input type=\"text\" name=\"name\">";
print "Ваше имя<p>\n";
print "<input type=\"password\" name=\"password1\">";
print "Ваш пароль<p>\n";
print "<input type=\"submit\" value=\"submit!\">\n</form>\n";
?>
|
========authorize.php====================
<?php
$lnk = mysql_connect('localhost', 'root', 'pass') or die ( 'Not connected : ' . mysql_error() );
mysql_select_db('BD', $lnk) or die ('Can\'t use foo : ' . mysql_error()); //boolean
mysql_query( 'SET NAMES cp1251' );
$result = mysql_query("SELECT name,pass FROM site_clients", $lnk) or die(mysql_error());
while ($f = mysql_fetch_array($result, MYSQL_ASSOC))
{
if ($f["name"]==$_POST['name'] && $f["pass"]==$_POST['password1'])
{
session_start();
$_SESSION['site_user'] = $f["name"];
header("Location: http://www.test.ru/script.php/");
break;
}
else echo"Введен неверный пароль или логин!";
}
?>
|
================script.php===============
<?php
session_start();
if(!isset($_SESSION['site_user']))
{
header("Location: index.php");
exit;
}
echo " Привет,". $_SESSION['site_user'].", ты на script.php странице!";
unset($_SESSION['site_user']);
session_destroy();
?>
|
| |
|
|
|
|
|
|
|
для: Alexhoppus
(10.08.2009 в 23:58)
| | Принцип прост.
При запросе от клиента к любому серверу, на котором ограничен доступ, серверу необходимо определить, а является ли клиент тем, за кого себя выдает.
Для этого сервер обычно просит клиента отправить что-то такое, чем клиент может доказать, что это именно он, а не кто-то другой. То есть что-то такое, что хороший годный клиент в состоянии отправить, а плохой, поддельный - не в состоянии.
Что-то такое на русском языке названия не имеет, а на английском обычно обозначается словом credentials. Но дело не в словах, а в сути.
Что годный клиент отправляет серверу при обращении к authorize.php?
Почему негодный клиент этого отправить не может?
Что клиент отправляет серверу при обращении к script.php?
Почему негодный клиент этого отправить не может?
Это скорее Роме ответ. Но Вам тоже приготится. | |
|
|
|
|
|
|
|
для: Trianon
(11.08.2009 в 00:06)
| | >Что годный клиент отправляет серверу при обращении к authorize.php?
Личные данные. Логин и пароль. Пароль не только при авторизации, но даже и при регистрации можно закодировать на клиенте, чтобы кроме браузера и автора его никто не знал. Тогда получается логин и уже не пароль.
>Почему негодный клиент этого отправить не может?
Потому что не знает пароля.
>Что клиент отправляет серверу при обращении к script.php?
Куку, наверное.
>Почему негодный клиент этого отправить не может?
Потому что не знает пароля. | |
|
|
|
|
|
|
|
для: Рома
(11.08.2009 в 22:45)
| | >>Что годный клиент отправляет серверу при обращении к authorize.php?
>Личные данные. Логин и пароль.
Верно.
>Пароль при регистрации можно закодировать на клиенте, чтобы кроме браузера и автора его никто не знал.
Это чушь, но о ней потом.
>>Почему негодный клиент этого отправить не может?
>Потому что не знает пароля.
Верно.
>>Что клиент отправляет серверу при обращении к script.php?
>Куку, наверное.
Кукис - лишь транспорт.
Он отправляет идентификатор сессии в этой куке. Либо в параметре URL.
>>Почему негодный клиент этого отправить не может?
>Потому что не знает пароля.
Так ему и не надо пароль отправлять?
Ему идентификатор сессии достаточно отправить.
Чужой сессии. | |
|
|
|
|
|
|
|
для: Trianon
(11.08.2009 в 22:51)
| | Ничего не даст никакой идентификатор сессии. Про сессии речи не было. | |
|
|
|
|
|
|
|
для: Рома
(11.08.2009 в 23:02)
| | Я ссылался на текст в (10.08.2009 в 23:58)
А там сплошное $_SESSION .
Если Вы о чем-то другом - пожалте брицца код скрипта. | |
|
|
|
|
|
|
|
для: Trianon
(11.08.2009 в 23:11)
| | >идентификатор сессии в этой куке. Либо в параметре URL.
На мой взгляд не может быть совсем никакой безопасной авторизации , если клиент может передавать SID только в адрессной строке.
Или если такое применяется так и нужно сразу предупреждать всех что переходя на другие адреса они дарят все свои данные вместе с реферерами.
привязка ещё и к USER_AGENT ничего не меняет
привязка к IP сделает для некоторых основным занятием ввод пароля
остаётся SSL, Basic авторизация ....
Значит только кукисы , обязательные для авторизации,
плюс например ключ (тоже в cookies) для декриптования значения сравниваемого с хэшем пароля.Что сделает недостаточным угадать только сид
особо много и нету выбора в средствах | |
|
|
|
|
|
|
|
для: heed
(11.08.2009 в 23:46)
| | >>идентификатор сессии в этой куке. Либо в параметре URL.
>
>На мой взгляд не может быть совсем никакой безопасной авторизации , если клиент может передавать SID только в адрессной строке.
Безусловно. Если SID является единственным параметром аутентификации - безусловно. Поскольку URL где только не остаются лежать.
>Или если такое применяется так и нужно сразу предупреждать всех что переходя на другие адреса они дарят все свои данные вместе с реферерами.
Проще не применять такое.
>привязка ещё и к USER_AGENT ничего не меняет
Как сказать. Осложнить методику атаки может.
>привязка к IP сделает для некоторых основным занятием ввод пароля
Если в течение сессии у клиента меняется IP - то это очень некоторый клиент. Настолько некоторый, что может обеспокоиться проблемой основного занятия.
Если от сессии к сессии - авторизации не мешает.
>остаётся SSL, Basic авторизация ....
>Значит только кукисы , обязательные для авторизации,
>плюс например ключ (тоже в cookies) для декриптования значения сравниваемого с хэшем пароля.Что сделает недостаточным угадать только сид
правильное слово - Дешифрование.
Только я не понял зачем что-то шифровать.
>особо много и нету выбора в средствах
Это верно.
Фактически основной канал - кукис.
Другое дело - что в нем держать. | |
|
|
|
|
|
|
|
для: Trianon
(11.08.2009 в 22:51)
| | >>Пароль при регистрации можно закодировать на клиенте, чтобы кроме браузера и автора его никто не знал.
>Это чушь, но о ней потом.
А что тогда не чушь?
Как все таки сложно от вас чего-то добиться... | |
|
|
|
|
|
|
|
для: Рома
(11.08.2009 в 23:29)
| | >>>Пароль при регистрации можно закодировать на клиенте, чтобы кроме браузера и автора его никто не знал.
>>Это чушь, но о ней потом.
Кодирование, шифрование, хеширование - это три большие разницы.
Не надо путать термины.
Даже четыре - с учетом того, что хеширование и вычисление дайджеста сообщения - тоже вещи несколько отличающиеся.
>А что тогда не чушь?
остальное было вполне здраво сказано.
>Как все таки сложно от вас чего-то добиться...
А чего Вы пытаетесь из-под меня добиться? Может я не понимаю чего? | |
|
|
|
|
|
|
|
для: Trianon
(11.08.2009 в 23:46)
| | >А чего Вы пытаетесь из-под меня добиться? Может я не понимаю чего?
Это я с вами я уже ничего не понимаю.
Если вы допускаете в системе авторизации вход по куке, значит кука является достоверным фактором знания пароля на 90%. В остальных десяти процентах ее могли украсть. В этом случае перед изменением личных настоек можно попросить ввести пароль заново.
Каким образом сессии могут повлиять на авторизацию, которая происходит за счет пары переменных кукисов - непонятно. Разве что вводить пароль и получать доступ до закрытия браузера. | |
|
|
|
|
|
|
|
для: Рома
(13.08.2009 в 00:32)
| | имхо сессия ,кроме того что выдаёт "уникальный" 32х битный код , позволяет не таскать с клиента и обратно целую кучу переменных,
"уникальный" в кавычках потомучто бывают случаи когда закэшированный кем-то сид через какое-то время может совпасть с чужим
И упрощает код отсутствием проверок содержимого этих переменных , если скрипт её получил из запроса, проверил, сохранил в файл (если сессии на файлах), незачем её потом проверять снова и снова. чего нельзя сказать о куках
.
Если чтото кудато вводить, то сессии тоже не помешают, чтобы чейто скрипт не навводил куда-нибудь несколько тысяч раз, или чтобы не происходило повторной обработки при нечаяном нажатии F5 | |
|
|
|
|
|
|
|
для: Trianon
(11.08.2009 в 23:46)
| | Да не, брешу - все я понял. Вся моя проблема заключалась в том, что я упустил разницу между пользовательской частью и админской - хотел подвести все под одну черту. Напрасно. Спасибо, что заставили подумать.
Давайте теперь опустим админскую часть и обсудим пользовательскую.
Регистрируясь, пользователь расчитывает на нашу честность и что его личные данные никто не узнает. Хотя некоторым это наверное не нужно. Значит пользователю нужно предоставить выбор между обычной аутентификацией и безопасной. Вот тут встает вопрос, о котором я уже говорил, но так и не одного мнения не услышал - может все-таки стоит хэшировать пароль пользователя при регистрации? Если да, то как это сделать наикрасивейше? | |
|
|
|
|
|
|
|
для: Рома
(13.08.2009 в 22:41)
| | > Вот тут встает вопрос, о котором я уже говорил, но так и не одного мнения не услышал - может все-таки стоит хэшировать пароль пользователя при регистрации?
В смысле - на клиентской стороне?
Javascript'ом? | |
|
|
|
|
|
|
|
для: Trianon
(13.08.2009 в 23:15)
| | Смеётесь? Я знаю что яваскриптом. Просто если я при регистрации высылаю челендж, шифрую пароль, отправляю это дело на сервер, там сохраняю и то и другое, то при авторизации мне приходится высылать не только челендж авторизации, но и челендж регистрации, потом привести пароль в нужный вид при помощи челенджа регистрации, и зашифровать его с помощью челенджа авторизации.
Это нормально, или я сильно зациклился на защите? Только честно :)) | |
|
|
|
|
|
|
|
для: Рома
(13.08.2009 в 23:27)
| | Я и не думал смеяться.
Спросил, чтобы убедиться, верно ли понял мысль. | |
|
|
|
|
|
|
|
для: Рома
(13.08.2009 в 23:27)
| | >Просто если я при регистрации высылаю челендж, шифрую пароль, отправляю это дело на сервер,
Помедленнее.
Во-первых, давайте вместо "я" будет стоять название стороны (либо клиент либо сервер)
Во вторых, высылает челендж и хеширует (а не шифрует) пароль - разные стороны. | |
|
|
|
|
|
|
|
для: Trianon
(14.08.2009 в 00:58)
| | Давайте завтра. Время поздно. | |
|
|
|
|
|
|
|
для: Рома
(14.08.2009 в 01:02)
| | Не вопрос :) | |
|
|
|
|
|
|
|
для: Trianon
(14.08.2009 в 00:58)
| | Моя вчерашняя теория не будет работать стабильно, иначе уже давно была бы реализована. Если при "частично защищенной авторизации с помощью JS" можно авторизовать пользователя что с включенным JS, что с выключенным, то "частично защищенная регистрация с помощью JS" при отключении этого JS рушится, точнее потом невозможно будет авторизоваться. Разве что предупреждать об этом пользователя.
А выглядит это так.
Клиент просит страницу регистрации, сервер генерит случайную строку, сохраняет ее в сессию и отправляет вместе с формой скрытым_полем_1. Перед отправкой данных клиент с помощью JS делает MD5(скрытое_поле_1 + MD5(password)). Сервер сохраняет логин, скрытое_поле_1 и полученный хэш.
При авторизации клиент просит страницу, сервер генерирует случайную строку, сохраняет ее в сессию и отправляет вместе с формой скрытым_полем_2. После ввода логина, клиет с помощью ajax подключается к серверу, по логину достает из базы сохраненное скрытое_поле_1 и подгружает его в форму. После нажатия submit клиент осуществляет MD5(скрытое_поле_2 + MD5(скрытое_поле_1 + MD5(password))).
Плюс: Пароль всегда передается только хэшем.
Минус: Не работает при отключенном JS. И вообще заморочка.
Остальные ситуации думаю можно урегулировать и подкорректировать.
Можно пойти другим путем, и при регистрации отправлять на сервер просто MD5(password). Никаких заморочек, результат тот же - пароль всегда передается только хэшем. | |
|
|
|
|
|
|
|
для: Рома
(14.08.2009 в 13:32)
| | И что с того? В базу-то всё равно попадёт хеш, а не пароль. И при логине можно будет отключить js и в поле с паролем вписать этот хеш. Вы всего лишь перенесли реализацию часть логики на клиента. | |
|
|
|
|
|
|
|
для: Саня
(14.08.2009 в 13:55)
| | . | |
|
|
|
|
|
|
|
для: Рома
(14.08.2009 в 13:32)
| | Какую роль играет факт генерации элемента скрытое_поле_1 на серверной стороне?
У меня просьба, описывая диалог в протоколе, пишите действия каждой из сторон на отдельной строке. Иначе протокол очень тяжело читать. | |
|
|
|
|
|
|
|
для: Trianon
(14.08.2009 в 20:13)
| | >Какую роль играет факт генерации элемента скрытое_поле_1 на серверной стороне?
Чтоб усложнить расшифровку пароля. Хотя мне самому это не очень нравиться, как то не гармонично.
Скажите, я хренью занимаюсь? Просто я нигде еще не видел, чтобы при регистрации хешировался пароль на клиенте. | |
|
|
|
|
|
|
|
для: Рома
(14.08.2009 в 20:29)
| | Да нет, почему же.
Если Вы посмотрите методику аутентификации в IMAP (метод DIGEST-MD5 в SMTP ) , то увидите, что авторы также ориентировались на предварительное хеширование пароля на стороне клиента.
Но этот первый фрагмент, который при авторизации играет роль челенджа (исследующей строки сервера) в процессе генерации пароля поручать серверу какой смысл?
Сам фрагмент, кстати, полезен. Иначе короткие пароли будут подбираться через rainbow-tables. | |
|
|
|
|
|
|
|
для: Trianon
(11.08.2009 в 22:51)
| | - Ему идентификатор сессии достаточно отправить.
Наверное тут поможет небольшой кусок кода, который будет регенерировать идентификатор через session_regenerate_id(), тогда уж знать идентификатор чужой сессии злоумышленник не сможет наверняка. | |
|
|
|
|
|
|
|
для: Alexhoppus
(11.08.2009 в 23:31)
| | Trianon , может подскажите тогда алгоритм условно безопасной авторизации?
идентификатор сессии лежит в сессионной куки, с ним сверяется скрипт на сервере. что еще следует хранить/проверять при авторизации и перемещению по страницам? | |
|
|
|
|
|
|
|
для: moonfox
(12.08.2009 в 01:38)
| | что-то, что зависит как от параметров сеанса, так и от отклика сервера в момент аутентификации логина.
Хранить и проверять - вещи разные. | |
|
|
|
|
|
|
|
для: moonfox
(12.08.2009 в 01:38)
| | Нашел следующий механизм защиты. Если в запросе отсылаемом пользователем содержится (вообще говоря необязательный заголовок) User-agent, то вдальнейшем, используя элемент массива $_SERVER['HTTP_USER_AGENT'], можно проверяить параметры системы человека, который заходит под тем или иным уникальным идентификатором, если они окажутся разными вернуть на ввод пароля. Вот например:
<?php
session_start();
$_SESSION['HTTP_USER_AGENT'] = md5($_SERVER['HTTP_USER_AGENT']);
?>
|
сохранили хэш код параметров системы пользователя.
<?php
session_start();
if ( md5($_SERVER['HTTP_USER_AGENT']) != $_SESSION['HTTP_USER_AGENT'] ) {
/* Запрос пароля */
exit;
}
/* Остальной код */
?>
|
При старте сессии проверяем, чтобы параметры системы содержащиеся в $_SESSION['HTTP_USER_AGENT'] были прежними, иначе возвращаем на ввод пароля. | |
|
|
|
|
|
|
|
для: Alexhoppus
(12.08.2009 в 13:57)
| | Respect
аналогично и с IP | |
|
|
|
|
|
|
|
для: Alexhoppus
(12.08.2009 в 13:57)
| | это от кражи сессии? | |
|
|
|
|
|
|
|
для: psychomc
(14.08.2009 в 14:32)
| | От подделки (если кто-то узнает SID кого-то и зайдет под ним) | |
|
|
|
|
|
|
|
для: alexhoppus
(19.08.2009 в 23:47)
| | Извините, что не прочитал это всё (я бы здох), но есть виды HTTP-авторизации. Два основных вида - Basic и Digest. Здесь можно прочитать про защищённый метод Digest: http://xakep.ru/post/27203/default.asp Там есть и готовый код. Вот улучшенный код:
====== security.php ======
<?php
############################################################# #### ####
#### == Digest Authentication == #### # # ####### ## # ####### ######
#### Made by: ][akep Online (xakep.ru) #### # # #_____# ##__ # ##__ #____#
#### Modernization: ~AquaZ~ #### # # #-----# ##--# ##-- #
############################################################# #### #### # # ## ## ###### #
# | -- Changes -- |
# | All data saving to 1 (one) file |
# | in serialized and compressed |
# | (deflated) array. |
# | |
# | Data that living more than |
# | 30 min. automatically dies |
# | |
# | Script optimized |
# | |
# | Script can get IP |
# | from HTTP_X_FORWARDED_FOR |
# |_________________________________|
function authorize($realm,$file,$userlist,$target){
$nonce = ip2long(getip()).time();
$headers = apache_request_headers();
$auth_success = false;
$stale = "false";
if (isset($headers['Authorization'])){
$authorization = $headers['Authorization'];
preg_match_all('/(,|\s|^)(\w+)=("([^"]*)"|([\w\d]*))(,|$)/',$authorization,$matches,PREG_SET_ORDER);
for ($i = 0; $i < count($matches); $i++){
$match = $matches[$i];
$auth_params[$match[2]] = $match[4] . $match[5];
}
$a1 = $auth_params['username'] . ':' . $auth_params['realm'] . ':' . $userlist[$auth_params['username']];
$a2 = $_SERVER['REQUEST_METHOD'] . ':' . $_SERVER['REQUEST_URI'];
$resp = md5(md5($a1) . ':' . $auth_params['nonce'] . ':' . md5($a2));
if ($resp == $auth_params['response']){
$arr = unserialize(gzinflate(file_get_contents($file)));
if (long2ip($arr[$auth_params['nonce']][0]) == $_SERVER['REMOTE_ADDR']){
unset($arr[$auth_params['nonce']]);
file_put_contents($file,gzdeflate(serialize($arr)));
$auth_success = true; // Аутентификация пройдена
} else {
$stale = "true";
}
}
}
if (!$auth_success) die;
}
##############################################################
#### == Simple IP getter == ####
#### Made by: ~AquaZ~ ####
##############################################################
function getip(){
$ip = getenv('HTTP_X_FORWARDED_FOR');
if (!$ip || ($ip == 'undefined') || empty($ip)) $ip = $_SERVER['REMOTE_ADDR'];
return $ip;
}
##############################################################
#### == Digest Authentication rubbish killer == ####
#### Made by: ~AquaZ~ ####
##############################################################
Mycop_Hax($file);
function Mycop_Hax($file,$maxlive = 1800){
$f = unserialize(gzinflate(file_get_contents($file)));
if (is_array($f)){
foreach($f as $key => $val){
if ($val[1] < time() - $maxlive) unset($f[$key]);
}
unlink($file);
file_put_contents($file,gzdeflate(serialize($f)));
}
}
?>
|
==== Начало защищённого файла (до вывода информации; если security.php лежит в inc/) ====
<?php require 'inc/security.php'; authorize('Название зоны','inc/temp.tmp',$userlist);
|
Первый параметр - имя защищённой зоны. Второй - файл с мусором, может быть любой. Самоочищается. Третий - ассоциативный массив
$userlist['логин'] = 'пароль'
|
| |
|
|
|