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


Короткий

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

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

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

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

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();
                }
            }
        }
Author: Tural Ali, 2012-01-18

4 answers

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

Http - это протокол без сохранения состояния. Маркер аутентификации должен сохраняться, чтобы сохранить состояние. Правильный способ - использовать сеанс. Теперь как вы отслеживаете сеанс? Это зависит от тебя. Но печенье - это неплохо.

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

 2
Author: Shiplu Mokaddim, 2012-01-18 09:46:00

Для установки временной задержки между попытками входа в систему (для предотвращения атак с применением грубой силы) и ограничения количества попыток

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

Для восстановления идентификатора сеанса почти при каждой операции

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

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

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

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

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

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

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

 8
Author: symcbean, 2012-01-18 09:29:50

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

 3
Author: chiborg, 2012-01-18 08:53:43

Файлы cookie - лучшее решение. Проверьте следующий код:

<form action="" method="post" id="frmLogin">
<div class="error-message"><?php if(isset($message)) { echo $message; } ?></div>    
<div class="field-group">
    <div><label for="login">Username</label></div>
    <div><input name="member_name" type="text" value="<?php if(isset($_COOKIE["member_login"])) { echo $_COOKIE["member_login"]; } ?>" class="input-field">
</div>
<div class="field-group">
    <div><label for="password">Password</label></div>
    <div><input name="member_password" type="password" value="<?php if(isset($_COOKIE["member_password"])) { echo $_COOKIE["member_password"]; } ?>" class="input-field"> 
</div>
<div class="field-group">
    <div><input type="checkbox" name="remember" id="remember" <?php if(isset($_COOKIE["member_login"])) { ?> checked <?php } ?> />
    <label for="remember-me">Remember me</label>
</div>
<div class="field-group">
    <div><input type="submit" name="login" value="Login" class="form-submit-button"></span></div>
</div>       

session_start();
if(!empty($_POST["login"])) {
    $conn = mysqli_connect("localhost", "root", "", "blog_samples");
    $sql = "Select * from members where member_name = '" . $_POST["member_name"] . "' and member_password = '" . md5($_POST["member_password"]) . "'";
    $result = mysqli_query($conn,$sql);
    $user = mysqli_fetch_array($result);
    if($user) {
            $_SESSION["member_id"]         = $user["member_id"];

            if(!empty($_POST["remember"])) {
                setcookie ("member_login",$_POST["member_name"],time()+ (10 * 365 * 24 * 60 * 60));
                setcookie ("member_password",$_POST["member_password"],time()+ (10 * 365 * 24 * 60 * 60));
            } else {
                if(isset($_COOKIE["member_login"])) {
                    setcookie ("member_login","");
                }
                if(isset($_COOKIE["member_password"])) {
                    setcookie ("member_password","");
                }
            }
    } else {
        $message = "Invalid Login";
    }
}
 -1
Author: Niby, 2018-09-05 05:50:41