5

我想知道 Web 应用程序通常遵循的过程来维护多个请求之间的登录,以及它们如何使用 COOKIES 管理事物。

在我的登录表单中,我提供了“记住我”功能。

当用户登录时,我从数据库中检查用户名和密码的有效性。如果它有效,那么我检查是否选择了“记住我”,如果是,则将用户名和密码存储在会话中,加密格式。最后将用户名和密码存储在 SESSION 中。

当用户从一个页面导航到另一个页面时,首先我运行登录检查脚本来检查 cookie 中是否有任何值,然后验证数据库中的用户名和密码,以检查其有效性。如果 cookie 中没有值并且会话中有一些值,那么我正在获取会话值而不是从 db 中检查它。

我没有检查会话值表单 db 不要不必要地点击 db,加快速度。如果是 cookie,它们可以被修改,所以需要检查。

这就是我的概念,对吗?这是要走的路吗?通常是像SO这样的网站,以及其他关于这种方法的作品?

或者网站在每个页面加载时检查登录真实性,无论是在会话中还是在 cookie 中?

请检查并给出您对此方案的想法和概念。

谢谢!

4

1 回答 1

14

首先,只需跟踪是否有人登录。之后,我们将处理“记住我”功能。

要知道是否有人登录,只需查看$_SESSION数组即可。里面的所有东西都是因为你之前把它放在那里的。因此,在处理登录表单时,如果用户名和密码正确,那么您将用户名、用户 ID 或其他任何内容存储在会话 ( $_SESSION['username'] = $username;) 中。

每当用户加载任何页面时,您只需检查

if (isset($_SESSION['username'])) {
    // $_SESSION['username'] is logged in
} else {
    // nobody is logged in
}

没有必要将密码存储在$_SESSION(实际上,出于安全目的,最好不要将其存储在数据库中以外的任何地方)。

现在,“记住我”功能......首先,一些注意事项:

  • 任何用户都可以修改其浏览器的 cookie,因此您需要确保发送到应用程序的 cookie 未被篡改。
  • 用户可以在公共计算机(图书馆等)上进行检查,因此您需要一个系统来使其无效。
  • 如果用户退出您的应用程序,则必须删除记住他/她的 cookie。

对于第一点,假设您在 cookie 上存储要“记住”的用户的用户名(非常不安全!!)。这意味着,如果任何用户为您的 Web 应用程序创建了一个包含“joe”内容的 cookie,您的应用程序将认为该用户 joe 已在该计算机中被记住,因此授予该攻击者访问权限,就好像他/她是 joe。因此,我们需要以某种方式加密/散列 cookie。

对于第二点,在某些计算机上使“记住我”无效,我们将以某种方式使用密码。如果某个用户想要使他/她可能选中“记住我”复选框的所有计算机无效,他/她所要做的就是更改他/她的密码。这也意味着如果他/她更改了他/她的密码,出于同样的原因,他/她的所有保存的登录信息都将失效。但安全总比后悔好...

因此,当您处理登录并且用户名和密码正确,并且选中“记住我”选项时,除了将用户名保存在会话中之外,您还存储了用户名和密码的哈希值(如果您将)在您发送给用户的 cookie 中。此外,您需要将用户名以纯文本(或以可逆方式加密)存储在 cookie 中,以了解哪个用户正在尝试通过 cookie “登录”,并检查 cookie 中用户名和密码的哈希值数据库中的用户名和密码。如果该检查是正确的,那么您将用户名存储在会话中并且不再检查该用户的 cookie(至少对于该会话)。

因此,总体而言,您的代码可能如下所示:

登录.php

if (check_login($_POST['username'], $_POST['password'])) {
    // login correct
    $_SESSION['username'] = $_POST['username'];
    if (isset($_POST['remember_me'])) {
        // we hash the password because we **NEVER** store it in plain text anywhere
        // so when we would like to check if the cookie value is correct, we will not
        // be able to do so if the hash in the cookie was done from the plaintext
        // password.
        $value = sprintf('%s:%s', $_POST['username'], md5($_POST['username'].hash_password($_POST['password'])));
        setcookie('rememberme', $value);
    }
    redirect('/your/home/page.php'); // view Post/Redirect/Get design pattern
} else {
    // login incorrect, show error message and whatever...
}

在每个 php 文件的开头(或者更好的是,在包含文件中以引导您的应用程序)

if (isset($_SESSION['username'])) {
    // $_SESSION['username'] is logged in, proceed as you wish
} else if (isset($_COOKIE['rememberme'])) {
    // this user has checked the remember me feature some time ago in a previous login.
    // let's check if it is valid.
    list($username, $hash) = explode(':', $_COOKIE['rememberme']);

    // we need to get the password hash stored for this user (remember you **NEVER** store passwords in plain text
    $pwd_hash = obtain_password_hash_from_username($username);
    if ($hash == sprintf('%s:%s', $username, md5($username.$pwd_hash))) {
        // yeah, the user remembered is correct. We'll save it to the session to not do this shit again
        $_SESSION['username'] = $username;
    } else {
        // the cookie value is not correct so maybe an attacker is trying to fool us,
        // or the user changed his password. Whatever it is, we remove the cookie
        // because it's no longer valid
        setcookie('rememberme', '', time() - 3600);
    }

} else {
    // this user is neither logged in nor "remembered"
}

散列用户密码的方法取决于您。您可能喜欢纯 md5 或 sha、salted md5 或 sha(更好)或一些耗时的方法,如河豚(推荐)。我使用普通的 md5 对 cookie 进行哈希处理,但您可以选择前面描述的任何方法。

我想就是这样。

于 2011-02-23T19:44:31.127 回答