Форум: Форум PHPФорум ApacheФорум Регулярные ВыраженияФорум MySQLHTML+CSS+JavaScriptФорум FlashРазное
Новые темы: 0000000
Программирование. Ступени успешной карьеры. Авторы: Кузнецов М.В., Симдянов И.В. C++. Мастер-класс в задачах и примерах. Авторы: Кузнецов М.В., Симдянов И.В. PHP 5/6. В подлиннике. Авторы: Кузнецов М.В., Симдянов И.В. PHP 5. На примерах. Авторы: Кузнецов М.В., Симдянов И.В., Голышев С.В. Самоучитель PHP 5 / 6 (3 издание). Авторы: Кузнецов М.В., Симдянов И.В.
ВСЕ НАШИ КНИГИ
Консультационный центр SoftTime

Форум PHP

Выбрать другой форум

 

Здравствуйте, Посетитель!

вид форума:
Линейный форум Структурный форум

тема: Безопасность авторизации в PHP
 
 автор: Staaas   (02.01.2005 в 13:37)   письмо автору
 
 

Народ! Посмотрите на мой скрипт авторизации с помощью сессий, может кто найдет дыру в авторизации.

Файл login.php для входа в систему
<?php

Include ("include/settings.php");

$server_name $HTTP_SERVER_VARS['SERVER_NAME'];
$http_referer $HTTP_SERVER_VARS['HTTP_REFERER'];
$login $HTTP_POST_VARS['login'];
$password $HTTP_POST_VARS['password'];
print 
"<br>".$server_name;
print 
"<br>".$http_referer;
print 
"<br>".$db_hostname;
print 
"<br>".$db_username;
print 
"<br>".$db_password;

if (
eregi("$server_name",$http_referer)){

    if ((
$submit) and (ereg("[A-Za-z0-9]",$login)) and (ereg("[A-Za-z0-9]",$password))){
        if (
mysql_connect($db_hostname,$db_username,$db_password))
        {
            if (!
mysql_select_db($db_tablename))
            {
                echo 
"Error select MySQL DB";
                exit;
            }
            
$query "SELECT DISTINCT Username, Status, Maillist, Fio FROM ".$prifex."mail_managers WHERE Username = '".$login."' and Password = '".md5($password)."';";
            
$r mysql_query($query);
            
mysql_close();
            if (
$r)
            {
                
$id md5(rand(10000,99999));
                
session_start();
                
$HTTP_SESSION_VARS["auth"] = 1;
                
$HTTP_SESSION_VARS["status"] = mysql_result($r,0,1);
                
$HTTP_SESSION_VARS["maillist"] = mysql_result($r,0,2);
                
header("Location: admin.php");
                exit;
            }
        }
        else
        {
            
header("Location: http://".$http_referer);
        }

    }
    else
    {
        
header("Location: http://".$http_referer);
    }
}
else
{
    print 
"<br>"."ref";
        
header("Location: http://".$server_name);
}
?>


Файл auth.php для проверки прошел ли пользователь авторизацию.

<?php
session_start
();

$auth $HTTP_SESSION_VARS["auth"];
$status $HTTP_SESSION_VARS["status"];
$maillist $HTTP_SESSION_VARS["maillist"];

if (
$auth != 1){
    unset(
$HTTP_SESSION_VARS["auth"]);
    unset(
$HTTP_SESSION_VARS["status"]);
    unset(
$HTTP_SESSION_VARS["maillist"]);
    
session_destroy();
    
header("Location: ".dirname($HTTP_SERVER_VARS['PATH_INFO']));
    exit;
}
?>

   
 
 автор: cheops   (02.01.2005 в 14:03)   письмо автору
 
   для: Staaas   (02.01.2005 в 13:37)
 

1) В SQL запросе:
<?php
$query 
"SELECT DISTINCT Username, Status, Maillist, Fio FROM ".$prifex."mail_managers WHERE Username = '".$login."' and Password = '".md5($password)."';";
?>

имеется переменная $prifex - она в settings.php определяется? Тогда следует проследить чтобы она была всегда инициирована.
2) Можно авторизоваться с другого хоста, создав на нём форму и указав в качестве action полный сетевой путь к login.php. Для исключения автоподбора пароля с друго хоста в форме следует разместить скрытое поле поместив туда идентификатор сессии, а в login.php проверить на соответствие текущего идентификатора и переданного методом POST.
3) Что произойдёт если в строке запроса просто набрать admin.php, минуя login.php?
4) Стоп... а у вас неправильно автризация происходит - попробуйте набрать неправильное имя и пароль - скрипт должен вас пустить. mysql_query($query) всегда возвращает дескриптор запроса, если SQL-запрос верен и возвращает FALSE только в случае ошибки в синтаксисе. Следует проверять не дескриптор, возвращённый mysql_query(), а число строк при помощи функции mysql_num_rows($r).

http://www.softtime.ru/dic/id_dic=122&id_group=2

   
 
 автор: Staaas   (02.01.2005 в 14:50)   письмо автору
 
   для: cheops   (02.01.2005 в 14:03)
 

Если в строке запроса набрать admin.php, то скрипт auth.php (код приведен выше)проверяет сначала прошел ли пользователь авторизацию, если нет, то перенаправляет на страницу ввода пароля.
Перемення $prifex указывается в settings.php.
По поводу подбора пароля с другого хоста, то перед началом проверки имя пользователя проверяется с какого хоста пришел запрос.

   
 
 автор: XPraptor   (05.01.2005 в 10:49)   письмо автору
 
   для: Staaas   (02.01.2005 в 14:50)
 

Мне ничего не помешает подставить нужный реферер при запросе, поэтому все же нужно сделать проверку, так как напи сали выше в ответе.

   
 
 автор: coloboc66   (05.01.2005 в 11:20)   письмо автору
 
   для: XPraptor   (05.01.2005 в 10:49)
 

Просветите меня- header() в файле login.php этого примера -служебная функция PHP или самодельная?

   
 
 автор: glsv (Дизайнер)   (05.01.2005 в 11:48)   письмо автору
 
   для: coloboc66   (05.01.2005 в 11:20)
 

Это функция PHP. С ее помощью можно отправлять HTTP-заголовки.

   
 
 автор: method   (30.06.2005 в 19:35)   письмо автору
 
   для: glsv (Дизайнер)   (05.01.2005 в 11:48)
 

cheops писал:
2) Можно авторизоваться с другого хоста, создав на нём форму и указав в качестве action полный сетевой путь к login.php. Для исключения автоподбора пароля с друго хоста в форме следует разместить скрытое поле поместив туда идентификатор сессии, а в login.php проверить на соответствие текущего идентификатора и переданного методом POST.

[1] А id сессии в скрытое поле как правильно поместить?так:

<?php
<input type="hidden" name="id" value=" <?php print session_id();?>">
?>


или так:

<?php
<input type="hidden" name="id" value=" <?php session_id();?>">
?>



<?php
if(session_id()!==$id){/*или сессия не запущена чтоб проверять id? тогда где её стартовать если это форма авторизации?сразу при обращении к старице?*/
session_unset();
session_destroy();
Header("location:index.php");
exit;
}
else{........}
?>


?????

[2]Влияет ли как то на безопасность размещение формы
и её обработчика в одном файле?

   
 
 автор: cheops   (01.07.2005 в 00:41)   письмо автору
 
   для: method   (30.06.2005 в 19:35)
 

1) Следует использовать первый вариант
<?php 
<input type="hidden" name="id" value=" <?php print session_id();?>"
?>

так как функция session_id() возвращает строку и не выводит значение в окно браузера.
2) Размещение формы и обработчика в одном файле на безопасность не влияет (если, конечно о безопасности позаботиться :).

   
 
 автор: method   (01.07.2005 в 06:01)   письмо автору
 
   для: cheops   (01.07.2005 в 00:41)
 

ведь можно на другом хосте в значении скрытого поля прописать
значение сессии посмотрев его (в опере например управление куками).....
или это ни чего не даст?

ЗЫ:посмотрите пожалуста коментарий в коде в верхнем моём посте...

   
 
 автор: cheops   (01.07.2005 в 09:15)   письмо автору
 
   для: method   (01.07.2005 в 06:01)
 

Да, это так, но время жизни сессии ограничено и ущерб будет не таким большим, как если бы форма была просто открыта.

Там где происходит обращение к сессии её следует иниициировать размещая функцию sesion_start() до любого вывода в окно браузера - лучше в самой первой строке.
<?php 
sesion_start
();
// Код
if(session_id()!==$id){/*или сессия не запущена чтоб проверять id? тогда где её стартовать если это форма авторизации?сразу при обращении к старице?*/ 
session_unset(); 
session_destroy(); 
Header("location:index.php"); 
exit; 

else{........} 
?>

   
 
 автор: method   (01.07.2005 в 11:52)   письмо автору
 
   для: cheops   (01.07.2005 в 09:15)
 

cheops
Да, это так, но время жизни сессии ограничено и ущерб будет не таким большим, как если бы форма была просто открыта.
но ведь данные же будут отправлены ? значит если это форма чата где поле
text readonly чужак который всё это проварачивает может обойти это readonly?
так получается?

   
 
 автор: method   (01.07.2005 в 12:03)   письмо автору
 
   для: method   (01.07.2005 в 11:52)
 

а может скрытому полю присвоить ip сервера, и проверять таким образом,
или чё то меня понесло вроде...=)
возможно ли такое?
если да то подскажите функцию которая определяет ip сервера ....

   
 
 автор: method   (01.07.2005 в 12:29)   письмо автору
 
   для: method   (01.07.2005 в 12:03)
 

ндя....точно я прогнал.....
тогда может как нибудь сравнивать и то и другое относительно
scriptname и его место расположения?

PS сейчас озадачен безопасностью приложения
которое не будет считаться доделаным пока не буду
уверен в его надёжной защите....

   
 
 автор: Гость..   (01.07.2005 в 14:45)
 
   для: method   (01.07.2005 в 12:29)
 

У меня была подобная проблема - как обезопасить форму от бутафорса, выход получился на мой взгляд довольно удачный... в БД создаешь дополнительный столбец, в котором указываешь колчичество неудачных попыток, когда неудачных попыток (за 10 минут) становится болше 3-х просто выводится надпись : отдохните 5-ть минут... после чего значение неудачных попыток войти просто обнуляется... на мой взгляд бутафорс в таком случае уже не чем не поможет....

   
 
 автор: method   (01.07.2005 в 15:07)   письмо автору
 
   для: Гость..   (01.07.2005 в 14:45)
 

Из статьи Владислава Путяка:

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

<?php sleep(1); //задержка на 1 секунду?>

Вот такие пироги....

А у меня чуть другая задача,пресечь отправку из форм
с других хостов, читай посты выше...

PS cheops вы где?

   
 
 автор: cheops   (01.07.2005 в 20:08)   письмо автору
 
   для: method   (01.07.2005 в 15:07)
 

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

   
 
 автор: method   (02.07.2005 в 06:57)   письмо автору
 
   для: cheops   (01.07.2005 в 20:08)
 

тогда может как нибудь сравнивать чё нить с чем нить относительно
scriptname и его место расположения?
вот такое даст гарантию:

<?php <form action="<?=$_SERVER["SCRIPT_NAME"]?>" method=POST>
?>

???

   
 
 автор: cheops   (02.07.2005 в 11:37)   письмо автору
 
   для: method   (02.07.2005 в 06:57)
 

Нет, так как у злоумышленика будет своя собственная копия формы, в которую он подствит те, значения которые захочет, или он вообще не будет прибегать к HTML-форме и сделает всё через сокеты, напрямую обращаясь к обработчику.

   
 
 автор: method   (02.07.2005 в 13:45)   письмо автору
 
   для: cheops   (02.07.2005 в 11:37)
 

cheops скажите не томите если
знаете что нить кроме того что вы уже
посоветовали, т.е.

<?php 
<input type="hidden" name="id" value=" <?php print session_id();?>"
?>

   
 
 автор: TrunK   (02.07.2005 в 14:48)   письмо автору
 
   для: method   (02.07.2005 в 13:45)
 

Поставить проверку на то, с какого сайта пришли данные...

   
 
 автор: method   (02.07.2005 в 16:25)   письмо автору
 
   для: TrunK   (02.07.2005 в 14:48)
 

привидите пример....

   
 
 автор: cheops   (02.07.2005 в 17:19)   письмо автору
 
   для: TrunK   (02.07.2005 в 14:48)
 

Это как раз и решается при помощи прошивки сессии - помещение в скрытое поле уникальное значение, которое знает только сайт. method-у этого не достаточно.

PS Проблема в том, что HTML-форма на самом деле находится не на сервере - она отправляется клиенту и клиент, заполнив её отправляет данные на сервер. Поэтому данные всегда идут с клиентской машины. Поэтому можно поставить робот, который со скоростью 20 сообщений в минуту 24 часа в сутки будет постить сообщения... Вот, кстати, ещё одно решение - проверять сколько времени прошло с момента последнего помещения сообщения с данной сессии - если менее 5 секунд, не помещать повторные сообщения. Если таких попыток будет больше 10 - блокировать размещение сообщений с данной сессии.

   
 
 автор: cheops   (02.07.2005 в 17:13)   письмо автору
 
   для: method   (02.07.2005 в 13:45)
 

Нет другой автоматической проверки у вас не выйдет, не зависимо от того, знаю я это или нет :))) так как это не позволяет сам протокол HTTP - он не сессионный. Это означает, что сервер, отправившего HTML-форму клиенту, дальнейшая её судьба не волнует, с какого адреса придёт ответ, получал ли этот клиент перед этим форму, сокет ли обращается или какой другой зверь, Web-серверу совершенно наплевать. Именно для решения проблем, возникающих в этом случае были введены cookie и сессии. Ничего лучшего на настоящий момент нет.

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

   
 
 автор: method   (02.07.2005 в 17:41)   письмо автору
 
   для: cheops   (02.07.2005 в 17:13)
 

cheops как всегда премного благодарен за оч хороший ответ =)

ЗЫ:хотя мне показалось что раньше чем понедельник я его не услышу,
потому сгонял на пхп клаб пришлось региться и создавать такую ж тему.......
ну да ладно лишним не будет.....

спасибо!

   
Rambler's Top100
вверх

Rambler's Top100 Яндекс.Метрика Яндекс цитирования