Правильный способ использования функции "Запомнить меня" в PHP
Короткие
Работа с системой входа в систему и попытка реализовать функцию запоминания меня.
Недавно я изучал эту тему, читал кучу статей, постов, рассказов, романов, сказок (называя их так, потому что некоторые из них не содержат даже 1 строки кода, просто множество слов) о, уязвимости cookie, такие как фиксация, захват... и т.д.
И решил достичь следующих целей
- Чтобы установить временную задержку между попытками входа (чтобы предотвратить атаки с использованием bruteforce) и ограничить количество попыток
- Чтобы восстановить идентификатор сеанса почти в каждой операции
Но Я действительно смутил мою основную проблему: какой путь правильный, для функции "помни меня"? использовать файлы 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();
}
}
}
Ответы
Ответ 1
Но я действительно смутил мою основную проблему: какой путь правильный, для функции "помни меня"? использовать файлы cookie/сеанс/базу данных?
Http - это безъядерный протокалл. Идентификатор аутентификации должен сохраняться, чтобы сохранить состояние.
Правильный способ - использовать сеанс. Теперь, как вы отслеживаете сеанс? Это вам. Но файлы cookie неплохие.
В сеансе вы можете сохранить хэш, созданный из разных браузеров (пользовательский агент, os, разрешение экрана и т.д.), чтобы проверить, является ли токен из той же среды. Чем больше критериев вы сохраните, тем больше будет сложнее захватить. Btw вам нужен JavaScript, чтобы каждый раз получать дополнительную информацию.
Ответ 2
Чтобы установить временную задержку между попытками входа (чтобы предотвратить атаки с использованием bruteforce) и ограничить количество попыток
Итак, вы предоставляете метод для DOS по аккаунту?
Чтобы восстановить идентификатор сеанса почти на каждой операции
erm, no. Это на самом деле может победить объект. Вы всегда должны генерировать новый идентификатор, когда текущий идентификатор истек или когда пользователь аутентифицирован - иначе оставьте его в покое.
Но я действительно смутил мою основную проблему: какой путь правильный, для функции "помни меня"? использовать файлы cookie/сеанс/базу данных?
Так как вам нужно сохранить токен на клиенте, это означает "cookie" (если вам не нравится писать что-то действительно сложное с использованием локального хранилища). Поскольку вы не хотите показывать данные с помощью простой подстановки cookie/make, это означает, что это должно быть случайное значение. И для согласования сохраненного случайного значения это означает сохранение данных в серверах - возможно, в базе данных, поскольку должно быть возможно ссылаться на данные на основе идентификатора пользователя или на основе случайного значения.
Пока вы могли просто использовать не истекающий (или очень долгоживущий) сеанс, я бы держался подальше от этого - данные будут получать снежок - и рекомендуется обновлять данные сеанса время от времени.
Вам также нужно учитывать сценарий, когда пользователь хочет, чтобы вы помнили ее на двух разных компьютерах. Если вы используете только один токен "запомнить меня" для каждой учетной записи, то либо вам придется использовать одно и то же значение у обоих клиентов, либо удалить старый токен при создании нового (т.е. Пользователь может запоминаться только на одной машине).
пожалуйста, объясните свою идею по коду. Я не могу понять четко без кода
Нет. Мне платят, чтобы написать код; Если вы хотите, чтобы я написал код для вас, вам нужно будет заплатить мне. И код займет гораздо больше места и времени, чем описание выше.
Ответ 3
Если вам нужен пример функции "запомнить меня" с кодом, вы можете проверить мою библиотеку PHP на https://github.com/gbirke/rememberme