PHP в деталях

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


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

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

$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("Чтобы войти в пользовательскую часть сайта, надо ввести правильные имя и пароль. Если вы забыли пароль, вернитесь обратно и нажмите на ссылку \"забыл пароль\"n");

  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-адрес пользователя ? чтобы, например, соседу по офису нельзя было взять файл с кукой и зайти со своего компьютера).

Это всё, что я хотел сказать сегодня. Защита от подбора и сессии ? на следующей неделе.


Содержание раздела