Сегодняшняя запись будет о том, как защитить учетные записи от брута паролей. Скрипт простой, но почти нигде не применяется.
Допустим, что у нас уже имеется регистрация и авторизация. Таблица юзеров примерно такая: id, login, pass
Мы будем дополнять саму авторизацию, а именно: допишем модуль проверки количества неверных вводов паролей за время X.
Наверняка Ваша авторизация выглядит таким образам:
SELECT COUNT(*) FROM user WHERE login='$login' and pass='$pass'
Мы немного переделаем этот код, но для начала создадим таблицу, в которую будут записываться все данные о юзере, который вход в аккаунт
<?php
CREATE TABLE `enter` (
`id` int(11) NOT NULL auto_increment,
`dat` int(11) NOT NULL,
`last_dat` int(11) NOT NULL,
`ip` bigint(20) NOT NULL,
`ua` varchar(255) NOT NULL,
`user` int(11) NOT NULL,
`enter` enum('0','1') default '0',
`count_enter` smallint(6) NOT NULL default '1',
`see` enum('0','1') NOT NULL default '0',
PRIMARY KEY (`id`),
KEY `last_dat` (`last_dat`),
KEY `ip` (`ip`),
KEY `user` (`user`),
KEY `dat` (`dat`)
) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
/*
dat - дата первого посещения
last_dat - дата последнего посещения
ip - ip юзера
ua - браузер юзера
user - id юзера(кому принадлежит запись)
enter - успешен ли вход
count_enter - количество авторизаций
see - видел ли владелец аккаунта эту авторизацию
*/
Теперь о самой авторизации:
<?php
$dat=86400; // искать такой же ip и ua за указанное время
$dat2=600; // время, на которое блокируется аккаунт при бруте
define('IP',ip2long($_SERVER['REMOTE_ADDR']));
$error=array(); // создаем массив, в который будем записывать отказы авторизаций
if(isset($_REQUEST['login']) and isset($_REQUEST['pass'])){ // проверяем, переданы ли скрипту логин и пароль
$m=sql('SELECT id,pass FROM user WHERE login=? LIMIT 1',$_REQUEST['login']); // получаем id и пароль юзера
if(mysql_num_rows($m)){ // проверяем, получили ли мы результат
$m=mysql_fetch_assoc($m); // создаем массив
if(trim($_REQUEST['pass'])!=$m['pass']){ // сравниваем пароли, и если не равны, делаем следующее:
$enter=sql("SELECT id FROM enter WHERE dat>".(time()-$dat)." and enter='0' and user='".$m['id']."' and ip=? and ua=? LIMIT 1", IP, $_SERVER['HTTP_USER_AGENT']); // ищем запись за время $dat , проваленной авторизацией, юзером с id, который мы получили выше и ip с ua
if(!mysql_num_rows($enter)){ // если не найдено:
sql("INSERT INTO enter (dat,last_dat,ip,ua,user) VALUES (".time().",".time().",?,?,'".$m['id']."')", IP, $_SERVER['HTTP_USER_AGENT']); // то заносим данные в базу
}else{ // иначе
$enter=mysql_fetch_assoc($enter); // создаем массив из запроса
sql("UPDATE enter SET last_dat=".time().",count_enter=count_enter+'1',see='0' WHERE id='".$enter['id']."'"); // и обновляем существующую запись
}
$error[]='Пароль неверен!'; // заносим в массив сообщение об ошибке
}
if(mysql_result(sql("SELECT SUM(count_enter) FROM enter WHERE user='".$m['id']."' and last_dat>".(time()-$dat2)." and enter='0'"),0)>3){ // проверяем кол-во проваленных авторизаций за время $dat2
$error=array('Учетная запись временно блокирована системой антибрута паролей!'); // если кол-во этих записей больше 3, то пересоздаем массив с сообщениями о проваленной авторизацией
}
if(empty($error)){ // если массив с проваленными авторизациями пуст, то выполняем вход
$_SESSION['id']=$m['id']; // заносим в сессию id авторизовавшегося юзера
$_SESSION['logenter']=array(time(),0); // и создаем еще 1 массив. Для чего он нужен, написано ниже
echo 'Вы авторизовались успешно!';
// такая же операция, что и при вводе неверного пароля, но только уже при успешной авторизации
$enter=sql("SELECT id FROM enter WHERE dat>".(time()-$dat)." and user='".$m['id']."' and enter='1' and ip=? and ua=? LIMIT 1", IP, $_SERVER['HTTP_USER_AGENT']);
if(!mysql_num_rows($enter)){
sql("INSERT INTO enter (dat,last_dat,ip,ua,user,enter,see) VALUES (".time().",".time().",?,?,'".$m['id']."','1','1')", IP, $_SERVER['HTTP_USER_AGENT']);
}else{
$enter=mysql_fetch_assoc($enter);
sql("UPDATE enter SET last_dat=".time().",count_enter=count_enter+'1',see='1' WHERE id='".$enter['id']."'");
}
}
}else{$error[]='Указанного логина не существует!';}
}
if(!empty($error)){ // вывод сообщений о проваленной авторизации
echo implode('<br/>',$error);
}
Следующий код - код проверки авторизован ли юзер
<?php
if(isset($_SESSION['id'])){ // проверяем, авторизован ли юзер
$USER=sql("SELECT * FROM user WHERE id='".$_SESSION['id']."'"); // если он в базе
if(mysql_num_rows($USER)){ // если есть:
$USER=mysql_fetch_assoc($USER); // создаем массив из запроса
if($_SESSION['logenter'][0]<time()){ // проверяем, значение элемента массива из сессии меньше текущего времени. если верно, то:
$_SESSION['logenter'][1]=mysql_result(sql("SELECT SUM(count_enter) FROM enter WHERE user='".$_SESSION['id']."' and see='0'"),0); // выполняем проверку с подсчетом проваленных авторизаций, которые не виел владелец акка и заносим в другой элемент массива результат
$_SESSION['logenter'][0]=time()+60; // задаем текущее время
} // нужно это для того, чтобы не мучать mysql сервер, конкретнее: чтобы запросы выполнялись не каждый раз, когда обновляется страница, а раз в минуту
if($_SESSION['logenter'][1]){ // проверяем, если ли попытки брута акка
echo 'Ваша учетная запись '.$_SESSION['logenter'][1].' раз подверглась бруту пароля! <a href="/ссылка на просмотр логов авторизаций">Подробнее >></a>'; // выводим на экран сообщение о бруте
if($_SESSION['logenter'][1]>3){echo 'Вход в аккаунт временно заблокирован!';} // если значений больше 3, то выводим сообщение о том, что учетка блокирована от авторизаций
}
}else{$USER=false;}
}
Вот такая вот несложная конструкция поможет Вам защитить учетки Ваших юзверей от взлома. Ну а сам просмотр логов авторизаций думаю Вы сможете написать и без меня