Правильный способ использования функции «Запомнить меня» в PHP

короткий

Работа с системой входа в систему и попытка реализовать функцию «запомнить меня».

Недавно я изучал эту тему, читал кучу статей, сообщений, рассказов, романов, сказок (называя их так, потому что некоторые из них не содержат даже 1 строки кода, всего лишь множество слов) о уязвимостях cookie таких как фиксация, захват … и т. д.

И решил достичь следующих целей

  1. Чтобы установить временную задержку между попытками входа (чтобы предотвратить атаки с использованием bruteforce) и ограничить количество попыток
  2. Чтобы восстановить идентификатор сеанса почти на каждой операции

Но я действительно смутил мою основную проблему: какой путь правильный, для функции «помни меня»? использовать файлы cookie / сеанс / базу данных?

И, пожалуйста, объясните свою идею по коду (я не могу понять четко без кода)

детализированный

В настоящее время мой код выглядит так

Во время входа я использую следующую функцию для установки файлов cookie и сеанса

protected function validateUser($userid, $ckey=0, $rememmber=0) { session_start(); session_regenerate_id(true); //this is a security measure $_SESSION['user_id'] = $userid; $_SESSION['HTTP_USER_AGENT'] = md5($_SERVER['HTTP_USER_AGENT']); if (isset($remember) && $rememmber == 'on') { setcookie("user_id", $_SESSION['user_id'], time() + 60 * 60 * 24 * COOKIE_TIME_OUT, "/"); setcookie("user_key", sha1($ckey), time() + 60 * 60 * 24 * COOKIE_TIME_OUT, "/"); } return true; } 

Затем на защищенных пользовательских страницах проверка user_id с помощью user_id для извлечения всех важных данных о пользователе из db

 public function protect() { session_start(); /* Secure against Session Hijacking by checking user agent */ if (isset($_SESSION['HTTP_USER_AGENT'])) { if ($_SESSION['HTTP_USER_AGENT'] != md5($_SERVER['HTTP_USER_AGENT'])) { $this->signout(); exit; } } // before we allow sessions, we need to check authentication key - ckey and ctime stored in database /* If session not set, check for cookies set by Remember me */ if (!isset($_SESSION['user_id'])) { if (isset($_COOKIE['user_id']) && isset($_COOKIE['user_key'])) { /* we double check cookie expiry time against stored in database */ $cookie_user_id = $_COOKIE['user_id']; $stmt = $this->db->prepare("select `ckey`,`ctime` from `users` where `id` =?") or die($this->db->error); $stmt->bind_param("i", $cookie_user_id) or die(htmlspecialchars($stmt->error)); $stmt->execute() or die(htmlspecialchars($stmt->error)); $stmt->bind_result($ckey, $ctime) or die($stmt->error); $stmt->close() or die(htmlspecialchars($stmt->error)); // coookie expiry if ((time() - $ctime) > 60 * 60 * 24 * COOKIE_TIME_OUT) { $this->signout(); } /* Security check with untrusted cookies - dont trust value stored in cookie. /* We also do authentication check of the `ckey` stored in cookie matches that stored in database during login */ if (!empty($ckey) && is_numeric($_COOKIE['user_id']) && $_COOKIE['key'] == sha1($ckey)) { session_regenerate_id(); //against session fixation attacks. $_SESSION['user_id'] = $_COOKIE['user_id']; $_SESSION['HTTP_USER_AGENT'] = md5($_SERVER['HTTP_USER_AGENT']); } else { $this->signout(); } } else { if ($page != 'main') { header('Location:' . wsurl); exit(); } } } 

Но я действительно смутил мою основную проблему: какой путь правильный, для функции «помни меня»? использовать файлы cookie / сеанс / базу данных?

Http является безгосударственным протоколом. Идентификатор аутентификации должен сохраняться, чтобы сохранить состояние. Правильный способ – использовать сеанс. Теперь, как вы отслеживаете сеанс? Тебе решать. Но файлы cookie неплохие.

В сеансе вы можете сохранить хэш, созданный из разных критериев браузера (пользовательский агент, os, разрешение экрана и т. Д.), Чтобы проверить, является ли токен из той же среды. Чем больше критериев вы сохраните, тем больше будет сложнее захватить. Btw вам нужен JavaScript, чтобы каждый раз получать дополнительную информацию.

Чтобы установить временную задержку между попытками входа (чтобы предотвратить атаки с использованием bruteforce) и ограничить количество попыток

Итак, вы предоставляете метод для DOS по аккаунту?

Чтобы восстановить идентификатор сеанса почти на каждой операции

erm, no. На самом деле это может победить объект. Вы всегда должны генерировать новый идентификатор, когда текущий идентификатор истек или когда пользователь аутентифицирован – иначе оставьте его в покое.

Но я действительно смутил мою основную проблему: какой путь правильный, для функции «помни меня»? использовать файлы cookie / сеанс / базу данных?

Поскольку вам нужно сохранить токен на клиенте, это означает «cookie» (если вам не нравится писать что-то действительно сложное с использованием локального хранилища). Поскольку вы не хотите показывать данные с помощью простой подстановки cookie / make, это означает, что это должно быть случайное значение. И для согласования сохраненного случайного значения это означает сохранение серверов данных – возможно, в базе данных, поскольку должно быть возможно ссылаться на данные на основе идентификатора пользователя или на основе случайного значения.

Хотя вы могли бы просто использовать не истекающий (или очень долгоживущий) сеанс, я бы держался подальше от этого – данные будут снежки – и рекомендуется обновлять данные сеанса время от времени.

Вы также должны учитывать сценарий, когда пользователь хочет, чтобы вы помнили ее на двух разных компьютерах. Если вы используете только один токен «запомнить меня» для каждой учетной записи, то либо вам придется использовать одно и то же значение у обоих клиентов, либо удалить старый токен при создании нового (т. Е. Пользователь может запоминаться только на одной машине ).

объясните свою идею по коду. Я не могу понять ясно без кода

Нет. Мне платят, чтобы написать код; Если вы хотите, чтобы я написал код для вас, вам нужно будет заплатить мне. И код займет гораздо больше места и времени, чем описание выше.

Если вам нужен пример функции «запомнить меня» с кодом, вы можете проверить мою библиотеку PHP на странице https://github.com/gbirke/rememberme