我的web应用程序使用会话存储关于用户的信息,一旦他们登录,并维护这些信息,因为他们在应用程序内从页面到页面。在这个特定的应用程序中,我存储的人的user_id, first_name和last_name。

我想在登录时提供一个“让我登录”选项,在用户的机器上放置一个cookie,为期两周,当他们返回应用程序时,将以相同的细节重新启动他们的会话。

做这件事的最佳方法是什么?我不想在cookie中存储他们的user_id,因为这似乎会让一个用户很容易尝试和伪造另一个用户的身份。


生成一个散列,其中可能包含只有您知道的秘密,然后将其存储在您的DB中,以便与用户关联。应该工作得很好。

安全注意:基于确定性数据的MD5哈希的cookie是一个坏主意;最好使用从CSPRNG派生的随机令牌。有关更安全的方法,请参阅ircmaxell对这个问题的回答。

通常我会这样做:

User logs in with 'keep me logged in' Create session Create a cookie called SOMETHING containing: md5(salt+username+ip+salt) and a cookie called somethingElse containing id Store cookie in database User does stuff and leaves ---- User returns, check for somethingElse cookie, if it exists, get the old hash from the database for that user, check of the contents of cookie SOMETHING match with the hash from the database, which should also match with a newly calculated hash (for the ip) thus: cookieHash==databaseHash==md5(salt+username+ip+salt), if they do, goto 2, if they don't goto 1

当然,你可以使用不同的cookie名称等,你也可以改变cookie的内容,只是要确保它不容易创建。例如,你也可以在创建用户时创建user_salt,并将其放在cookie中。

你也可以用sha1代替md5(或者几乎任何算法)

我在这里问了这个问题的一个角度,答案将引导您找到所需的所有基于令牌的超时cookie链接。

基本上,您不会将userId存储在cookie中。您存储了一个一次性令牌(巨大的字符串),用户使用它来拾取旧的登录会话。然后,为了使其真正安全,在进行重大操作(比如更改密码本身)时,需要输入密码。

Implementing a "Keep Me Logged In" feature means you need to define exactly what that will mean to the user. In the simplest case, I would use that to mean the session has a much longer timeout: 2 days (say) instead of 2 hours. To do that, you will need your own session storage, probably in a database, so you can set custom expiry times for the session data. Then you need to make sure you set a cookie that will stick around for a few days (or longer), rather than expire when they close the browser.

我能听到你在问“为什么是2天?”为什么不是两周?”这是因为在PHP中使用会话会自动将过期时间向后推。这是因为在PHP中会话的过期实际上是一个空闲超时。

现在,我可能会实现一个更难的超时值,我将其存储在会话本身中,并在2周左右退出,并添加代码来查看并强制使会话无效。或者至少让他们退出。这意味着将要求用户定期登录。雅虎这是否。

我推荐Stefan提到的方法(即遵循改进的持久登录Cookie最佳实践中的指导方针),也建议你确保你的Cookie是HttpOnly Cookie,这样它们就不会被潜在的恶意JavaScript访问。

好吧,让我直截了当地说:如果你为了这个目的把用户数据,或者任何从用户数据衍生出来的东西放到cookie里,你就做错了。

在那里。我说了。现在我们来看看真正的答案。

你可能会问,哈希用户数据有什么问题?好吧,这归结于曝光表面和通过隐藏来保证安全。

想象一下,你是一个攻击者。您将看到为会话上的remember-me设置的加密cookie。它有32个字符宽。哇。那可能是MD5…

让我们再想象一下他们知道你用的算法。例如:

md5(salt+username+ip+salt)

现在,攻击者所需要做的就是强力破解“盐”(这并不是真正的盐,但稍后会详细介绍),他现在可以用他的IP地址的任何用户名生成他想要的所有假令牌!但是野蛮胁迫盐很难,对吧?绝对的。但现代gpu在这方面做得非常好。除非你在游戏中使用足够的随机性(游戏邦注:让游戏规模足够大),否则游戏便会迅速倒塌,并带走通往你城堡的钥匙。

简而言之,唯一能保护你的是盐,它并没有像你想象的那样保护你。

但是等等!

所有这些都是假设攻击者知道算法!如果是秘密和困惑,那你就安全了,对吧?错了。这种思路有一个名字:通过模糊获得安全,永远不应该依赖。

更好的方法

更好的方法是永远不要让用户的信息离开服务器,除了id。

当用户登录时,生成一个较大的(128 ~ 256位)随机令牌。将其添加到将令牌映射到用户id的数据库表中,然后将其发送到cookie中的客户端。

如果攻击者猜出了另一个用户的随机令牌怎么办?

我们来做一下计算。我们生成了一个128位的随机令牌。这意味着有:

possibilities = 2^128
possibilities = 3.4 * 10^38

现在,为了显示这个数字有多大,让我们想象一下,互联网上的每个服务器(假设今天是50,000,000)都试图以每秒1,000,000,000的速度强制执行这个数字。在现实中,您的服务器在这样的负载下会崩溃,但是让我们来看看。

guesses_per_second = servers * guesses
guesses_per_second = 50,000,000 * 1,000,000,000
guesses_per_second = 50,000,000,000,000,000

所以每秒要猜5千万亿次。这就是快!对吧?

time_to_guess = possibilities / guesses_per_second
time_to_guess = 3.4e38 / 50,000,000,000,000,000
time_to_guess = 6,800,000,000,000,000,000,000

6.8的10的10次方秒…

让我们试着把它降低到更友好的数字。

215,626,585,489,599 years

或者更好:

47917 times the age of the universe

是的,这是宇宙年龄的47917倍……

基本上,它不会裂开。

总结一下:

我推荐的更好的方法是将cookie存储为三部分。

function onLogin($user) {
    $token = GenerateRandomToken(); // generate a token, should be 128 - 256 bit
    storeTokenForUser($user, $token);
    $cookie = $user . ':' . $token;
    $mac = hash_hmac('sha256', $cookie, SECRET_KEY);
    $cookie .= ':' . $mac;
    setcookie('rememberme', $cookie);
}

然后,验证:

function rememberMe() {
    $cookie = isset($_COOKIE['rememberme']) ? $_COOKIE['rememberme'] : '';
    if ($cookie) {
        list ($user, $token, $mac) = explode(':', $cookie);
        if (!hash_equals(hash_hmac('sha256', $user . ':' . $token, SECRET_KEY), $mac)) {
            return false;
        }
        $usertoken = fetchTokenByUserName($user);
        if (hash_equals($usertoken, $token)) {
            logUserIn($user);
        }
    }
}

注意:不要使用令牌或用户和令牌的组合来查找数据库中的记录。始终确保根据用户获取记录,然后使用时间安全的比较函数来比较所获取的令牌。更多关于定时攻击的内容。

现在,非常重要的是,SECRET_KEY是一个加密秘密(由/dev/urandom之类的东西生成和/或从高熵输入派生)。此外,GenerateRandomToken()需要是一个强随机源(mt_rand()还不够强。使用一个库,如RandomLib或random_compat,或mcrypt_create_iv()与DEV_URANDOM)…

hash_equals()是为了防止定时攻击。 如果使用PHP 5.6以下的版本,则不支持hash_equals()函数。在这种情况下,你可以用timingSafeCompare函数替换hash_equals():

/**
 * A timing safe equals comparison
 *
 * To prevent leaking length information, it is important
 * that user input is always used as the second parameter.
 *
 * @param string $safe The internal (safe) value to be checked
 * @param string $user The user submitted (unsafe) value
 *
 * @return boolean True if the two strings are identical.
 */
function timingSafeCompare($safe, $user) {
    if (function_exists('hash_equals')) {
        return hash_equals($safe, $user); // PHP 5.6
    }
    // Prevent issues if string length is 0
    $safe .= chr(0);
    $user .= chr(0);

    // mbstring.func_overload can make strlen() return invalid numbers
    // when operating on raw binary strings; force an 8bit charset here:
    if (function_exists('mb_strlen')) {
        $safeLen = mb_strlen($safe, '8bit');
        $userLen = mb_strlen($user, '8bit');
    } else {
        $safeLen = strlen($safe);
        $userLen = strlen($user);
    }

    // Set the result to the difference between the lengths
    $result = $safeLen - $userLen;

    // Note that we ALWAYS iterate over the user-supplied length
    // This is to prevent leaking length information
    for ($i = 0; $i < $userLen; $i++) {
        // Using % here is a trick to prevent notices
        // It's safe, since if the lengths are different
        // $result is already non-0
        $result |= (ord($safe[$i % $safeLen]) ^ ord($user[$i]));
    }

    // They are only identical strings if $result is exactly 0...
    return $result === 0;
}

简介

你的标题“让我登录”-最好的方法让我很难知道从哪里开始,因为如果你正在寻找最好的方法,那么你必须考虑以下几点:

识别 安全

饼干

在常见的浏览器cookie盗窃漏洞和跨站点脚本攻击之间,我们必须接受cookie是不安全的。为了帮助提高安全性,您必须注意php setcookies具有额外的功能,例如

Bool setcookie (string $name [, string $value [, int $expire = 0 [, string $path [, string $domain [, Bool $secure = false [, Bool $httponly = false]]]]]])

secure(使用HTTPS连接) httponly(通过XSS攻击减少身份盗窃)

定义

令牌(长度为n的不可预知的随机字符串,例如。/dev/urandom) 参考(长度为n的不可预知的随机字符串,例如。/dev/urandom) 签名(使用HMAC方法生成键控哈希值)

简单的方法

一个简单的解决方案是:

用户使用“记住我”登录 带令牌和签名的登录Cookie 什么时候返回,检查签名 如果签名是ok ..然后在数据库中查找username & token 如果无效..返回登录页面 如果有效,自动登录

上面的案例研究总结了本页上所有的例子,但它们的缺点是

没有办法知道饼干是不是被偷了 攻击者可能是访问敏感操作,如更改密码或数据,如个人和烘焙信息等。 受损害的cookie在cookie生命周期内仍然有效

更好的解决方案

一个更好的解决办法是

用户已登录,并选中“记住我” 生成令牌和签名并存储在cookie中 令牌是随机的,仅对单个身份验证有效 令牌将在每次访问站点时替换 当一个未登录的用户访问网站时,签名、令牌和用户名将被验证 记住我的登录应该有限制的访问,不允许修改密码,个人信息等。

示例代码

// Set privateKey
// This should be saved securely 
$key = 'fc4d57ed55a78de1a7b31e711866ef5a2848442349f52cd470008f6d30d47282';
$key = pack("H*", $key); // They key is used in binary form

// Am Using Memecahe as Sample Database
$db = new Memcache();
$db->addserver("127.0.0.1");

try {
    // Start Remember Me
    $rememberMe = new RememberMe($key);
    $rememberMe->setDB($db); // set example database

    // Check if remember me is present
    if ($data = $rememberMe->auth()) {
        printf("Returning User %s\n", $data['user']);

        // Limit Acces Level
        // Disable Change of password and private information etc

    } else {
        // Sample user
        $user = "baba";

        // Do normal login
        $rememberMe->remember($user);
        printf("New Account %s\n", $user);
    }
} catch (Exception $e) {
    printf("#Error  %s\n", $e->getMessage());
}

类使用

class RememberMe {
    private $key = null;
    private $db;

    function __construct($privatekey) {
        $this->key = $privatekey;
    }

    public function setDB($db) {
        $this->db = $db;
    }

    public function auth() {

        // Check if remeber me cookie is present
        if (! isset($_COOKIE["auto"]) || empty($_COOKIE["auto"])) {
            return false;
        }

        // Decode cookie value
        if (! $cookie = @json_decode($_COOKIE["auto"], true)) {
            return false;
        }

        // Check all parameters
        if (! (isset($cookie['user']) || isset($cookie['token']) || isset($cookie['signature']))) {
            return false;
        }

        $var = $cookie['user'] . $cookie['token'];

        // Check Signature
        if (! $this->verify($var, $cookie['signature'])) {
            throw new Exception("Cokies has been tampared with");
        }

        // Check Database
        $info = $this->db->get($cookie['user']);
        if (! $info) {
            return false; // User must have deleted accout
        }

        // Check User Data
        if (! $info = json_decode($info, true)) {
            throw new Exception("User Data corrupted");
        }

        // Verify Token
        if ($info['token'] !== $cookie['token']) {
            throw new Exception("System Hijacked or User use another browser");
        }

        /**
         * Important
         * To make sure the cookie is always change
         * reset the Token information
         */

        $this->remember($info['user']);
        return $info;
    }

    public function remember($user) {
        $cookie = [
                "user" => $user,
                "token" => $this->getRand(64),
                "signature" => null
        ];
        $cookie['signature'] = $this->hash($cookie['user'] . $cookie['token']);
        $encoded = json_encode($cookie);

        // Add User to database
        $this->db->set($user, $encoded);

        /**
         * Set Cookies
         * In production enviroment Use
         * setcookie("auto", $encoded, time() + $expiration, "/~root/",
         * "example.com", 1, 1);
         */
        setcookie("auto", $encoded); // Sample
    }

    public function verify($data, $hash) {
        $rand = substr($hash, 0, 4);
        return $this->hash($data, $rand) === $hash;
    }

    private function hash($value, $rand = null) {
        $rand = $rand === null ? $this->getRand(4) : $rand;
        return $rand . bin2hex(hash_hmac('sha256', $value . $rand, $this->key, true));
    }

    private function getRand($length) {
        switch (true) {
            case function_exists("mcrypt_create_iv") :
                $r = mcrypt_create_iv($length, MCRYPT_DEV_URANDOM);
                break;
            case function_exists("openssl_random_pseudo_bytes") :
                $r = openssl_random_pseudo_bytes($length);
                break;
            case is_readable('/dev/urandom') : // deceze
                $r = file_get_contents('/dev/urandom', false, null, 0, $length);
                break;
            default :
                $i = 0;
                $r = "";
                while($i ++ < $length) {
                    $r .= chr(mt_rand(0, 255));
                }
                break;
        }
        return substr(bin2hex($r), 0, $length);
    }
}

在Firefox和Chrome中进行测试

优势

更好的安全性 攻击者访问受限 当cookie被盗时,它只对单次访问有效 当下一次原始用户访问该网站时,您可以自动检测并通知用户盗窃

缺点

不支持通过多个浏览器(移动和Web)进行持久连接 cookie仍然可以被窃取,因为用户只有在下次登录后才会收到通知。

快速修复

为每个必须有持久连接的系统引入审批系统 使用多个cookie进行认证

多重Cookie方法

当攻击者要窃取cookie时,唯一的焦点是一个特定的网站或域名。example.com

但实际上,您可以从2个不同的域(example.com & fakeaddsite.com)验证用户,并使其看起来像“广告Cookie”

用户使用“记住我”登录example.com 存储用户名,令牌,在cookie引用 存储用户名,令牌,在数据库引用等。Memcache 通过get和iframe发送引用id到fakeaddsite.com fakeaddsite.com使用引用从数据库获取用户和令牌 Fakeaddsite.com存储签名 当用户从fakeaddsite.com返回带有iframe的签名信息时 结合数据并进行验证 …你知道剩下的

有些人可能会想,你怎么能使用两个不同的cookie呢?这是可能的,想象example.com = localhost和fakeaddsite.com = 192.168.1.120。如果你检查饼干,它看起来是这样的

从上图来看

当前访问的站点是localhost 它还包含从192.168.1.120设置的cookie

192.168.1.120

只接受定义的HTTP_REFERER 只接受来自指定REMOTE_ADDR的连接 没有JavaScript,没有内容,但除了签名信息和从cookie中添加或检索它之外没有任何内容

优势

99%的情况下你都能骗过攻击者 您可以在攻击者第一次尝试时轻松锁定该帐户 与其他方法一样,在下次登录之前就可以阻止攻击

缺点

多个请求到服务器,只是为了一个登录

改进

使用iframe使用ajax完成

我的解是这样的。它不是百分之百的防弹,但我认为它在大多数情况下都能帮你。

当用户成功登录时,创建一个包含以下信息的字符串:

$data = (SALT + ":" + hash(User Agent) + ":" + username 
                     + ":" + LoginTimestamp + ":"+ SALT)

加密$data,设置类型为HttpOnly,并设置cookie。

当用户回到你的网站时,执行以下步骤:

Get cookie data. Remove dangerous characters inside cookie. Explode it with : character. Check validity. If cookie is older than X days then redirect user to login page. If cookie is not old; Get latest password change time from database. If password is changed after user's last login redirect user to login page. If pass wasn't changed recently; Get user's current browser agent. Check whether (currentUserAgentHash == cookieUserAgentHash). IF agents are same go to next step, else redirect to login page. If all steps passed successfully authorize username.

如果用户登出,请删除此cookie。如果用户重新登录,创建新的cookie。

我不理解在cookie中存储加密内容的概念,因为你需要进行黑客操作的正是它的加密版本。如果我遗漏了什么,请评论。

我正在考虑采用这种方法来“记住我”。如果你能看到任何问题,请评论。

Create a table to store "Remember Me" data in - separate to the user table so that I can log in from multiple devices. On successful login (with Remember Me ticked): a) Generate a unique random string to be used as the UserID on this machine: bigUserID b) Generate a unique random string: bigKey c) Store a cookie: bigUserID:bigKey d) In the "Remember Me" table, add a record with: UserID, IP Address, bigUserID, bigKey If trying to access something that requires login: a) Check for the cookie and search for bigUserID & bigKey with a matching IP address b) If you find it, Log the person in but set a flag in the user table "soft login" so that for any dangerous operations, you can prompt for a full login. On logout, Mark all the "Remember Me" records for that user as expired.

我能看到的唯一弱点是;

你就可以拿到别人的笔记本电脑,用cookie欺骗他们的IP地址。 你可以每次欺骗一个不同的IP地址,并猜出整个事情-但有两个大字符串来匹配,这将是…做类似于上面的计算…我不知道……巨大的机会吗?

旧的线程,但仍然是一个有效的关注。我注意到一些关于安全性的很好的回答,并避免使用“通过模糊实现安全性”,但在我看来,给出的实际技术方法还不够。在我提出我的方法之前,我必须说:

NEVER store a password in clear text...EVER! NEVER store a user's hashed password in more than one location in your database. Your server backend is always capable of pulling the hashed password from the users table. It's not more efficient to store redundant data in lieu of additional DB transactions, the inverse is true. Your Session ID's should be unique, so no two users could ever share an ID, hence the purpose of an ID (could your Driver's License ID number ever match another persons? No.) This generates a two-piece unique combination, based on 2 unique strings. Your Sessions table should use the ID as the PK. To allow multiple devices to be trusted for auto-signin, use another table for trusted devices which contains the list of all validated devices (see my example below), and is mapped using the username. It serves no purpose to hash known data into a cookie, the cookie can be copied. What we are looking for is a complying user device to provide authentic information that cannot be obtained without an attacker compromising the user's machine (again, see my example). This would mean, however, that a legitimate user who forbids his machine's static information (i.e. MAC address, device hostname, useragent if restricted by browser, etc.) from remaining consistent (or spoofs it in the first place) will not be able to use this feature. But if this is a concern, consider the fact that you are offering auto-signin to users whom identify themselves uniquely, so if they refuse to be known by spoofing their MAC, spoofing their useragent, spoofing/changing their hostname, hiding behind proxies, etc., then they are not identifiable, and should never be authenticated for an automatic service. If you want this, you need to look into smart-card access bundled with client-side software that establishes identity for the device being used.

话虽如此,在系统上有两种自动登录的好方法。

First, the cheap, easy way that puts it all on someone else. If you make your site support logging in with, say, your google+ account, you probably have a streamlined google+ button that will log the user in if they are already signed into google (I did that here to answer this question, as I am always signed into google). If you want the user automatically signed in if they are already signed in with a trusted and supported authenticator, and checked the box to do so, have your client-side scripts perform the code behind the corresponding 'sign-in with' button before loading, just be sure to have the server store a unique ID in an auto-signin table that has the username, session ID, and the authenticator used for the user. Since these sign-in methods use AJAX, you are waiting for a response anyway, and that response is either a validated response or a rejection. If you get a validated response, use it as normal, then continue loading the logged in user as normal. Otherwise, the login failed, but don't tell the user, just continue as not logged in, they will notice. This is to prevent an attacker who stole cookies (or forged them in an attempt to escalate privileges) from learning that the user auto-signs into the site.

这很便宜,也可能被一些人认为是肮脏的,因为它试图在不告诉你的情况下,在谷歌和Facebook等地方验证你可能已经登录的自我。然而,它不应该用于那些没有要求自动登录您的网站的用户,这种特殊的方法仅用于外部身份验证,如谷歌+或FB。

由于使用外部验证器在幕后告诉服务器用户是否经过验证,因此攻击者只能获得唯一ID,而唯一ID本身是无用的。我将详细说明:

User 'joe' visits site for first time, Session ID placed in cookie 'session'. User 'joe' Logs in, escalates privileges, gets new Session ID and renews cookie 'session'. User 'joe' elects to auto-signin using google+, gets a unique ID placed in cookie 'keepmesignedin'. User 'joe' has google keep them signed in, allowing your site to auto-signin the user using google in your backend. Attacker systematically tries unique IDs for 'keepmesignedin' (this is public knowledge handed out to every user), and is not signed into anywhere else; tries unique ID given to 'joe'. Server receives Unique ID for 'joe', pulls match in DB for a google+ account. Server sends Attacker to login page that runs an AJAX request to google to login. Google server receives request, uses its API to see Attacker is not logged in currently. Google sends response that there is no currently signed in user over this connection. Attacker's page receives response, script automatically redirects to login page with a POST value encoded in the url. Login page gets the POST value, sends the cookie for 'keepmesignedin' to an empty value and a valid until date of 1-1-1970 to deter an automatic attempt, causing the Attacker's browser to simply delete the cookie. Attacker is given normal first-time login page.

无论如何,即使攻击者使用了不存在的ID,除了接收到经过验证的响应外,所有尝试都应该失败。

对于那些使用外部验证器登录到站点的用户,此方法可以而且应该与内部验证器结合使用。

= = = = = = = = =

现在,对于您自己的可以自动登录用户的验证器系统,我是这样做的:

DB有几个表:

TABLE users:
UID - auto increment, PK
username - varchar(255), unique, indexed, NOT NULL
password_hash - varchar(255), NOT NULL
...

注意,用户名的长度可以是255个字符。我的服务器程序将系统中的用户名限制为32个字符,但外部身份验证者可能使用@域作为用户名。tld要比这个大,所以我只支持电子邮件地址的最大长度,以获得最大的兼容性。

TABLE sessions:
session_id - varchar(?), PK
session_token - varchar(?), NOT NULL
session_data - MediumText, NOT NULL

Note that there is no user field in this table, because the username, when logged in, is in the session data, and the program does not allow null data. The session_id and the session_token can be generated using random md5 hashes, sha1/128/256 hashes, datetime stamps with random strings added to them then hashed, or whatever you would like, but the entropy of your output should remain as high as tolerable to mitigate brute-force attacks from even getting off the ground, and all hashes generated by your session class should be checked for matches in the sessions table prior to attempting to add them.

TABLE autologin:
UID - auto increment, PK
username - varchar(255), NOT NULL, allow duplicates
hostname - varchar(255), NOT NULL, allow duplicates
mac_address - char(23), NOT NULL, unique
token - varchar(?), NOT NULL, allow duplicates
expires - datetime code

MAC addresses by their nature are supposed to be UNIQUE, therefore it makes sense that each entry has a unique value. Hostnames, on the other hand, could be duplicated on separate networks legitimately. How many people use "Home-PC" as one of their computer names? The username is taken from the session data by the server backend, so manipulating it is impossible. As for the token, the same method to generate session tokens for pages should be used to generate tokens in cookies for the user auto-signin. Lastly, the datetime code is added for when the user would need to revalidate their credentials. Either update this datetime on user login keeping it within a few days, or force it to expire regardless of last login keeping it only for a month or so, whichever your design dictates.

This prevents someone from systematically spoofing the MAC and hostname for a user they know auto-signs in. NEVER have the user keep a cookie with their password, clear text or otherwise. Have the token be regenerated on each page navigation, just as you would the session token. This massively reduces the likelihood that an attacker could obtain a valid token cookie and use it to login. Some people will try to say that an attacker could steal the cookies from the victim and do a session replay attack to login. If an attacker could steal the cookies (which is possible), they would certainly have compromised the entire device, meaning they could just use the device to login anyway, which defeats the purpose of stealing cookies entirely. As long as your site runs over HTTPS (which it should when dealing with passwords, CC numbers, or other login systems), you have afforded all the protection to the user that you can within a browser.

One thing to keep in mind: session data should not expire if you use auto-signin. You can expire the ability to continue the session falsely, but validating into the system should resume the session data if it is persistent data that is expected to continue between sessions. If you want both persistent AND non-persistent session data, use another table for persistent session data with the username as the PK, and have the server retrieve it like it would the normal session data, just use another variable.

Once a login has been achieved in this way, the server should still validate the session. This is where you can code expectations for stolen or compromised systems; patterns and other expected results of logins to session data can often lead to conclusions that a system was hijacked or cookies were forged in order to gain access. This is where your ISS Tech can put rules that would trigger an account lockdown or auto-removal of a user from the auto-signin system, keeping attackers out long enough for the user to determine how the attacker succeeded and how to cut them off.

最后注意,确保任何恢复尝试、密码更改或超过阈值的登录失败都会导致自动登录被禁用,直到用户正确验证并确认发生了这种情况。

如果有人期望在我的回答中给出代码,我很抱歉,这不会发生在这里。我会说我使用PHP, jQuery和AJAX来运行我的网站,我从不使用Windows作为服务器…永远。

我读了所有的答案,仍然发现很难提取我应该做什么。如果一张图片相当于1k个单词,我希望这有助于其他人实现基于Barry Jaspan的改进的持久登录Cookie最佳实践的安全持久存储

如果您有问题、反馈或建议,我将尝试更新图表,以反映试图实现安全持久登录的新手。

我认为你可以这样做:

$cookieString = password_hash($username, PASSWORD_DEFAULT);

将$cookiestring存储在DB中,并将其设置为cookie。还要将用户名设置为cookie。哈希的全部意义在于它不能被逆向工程。

当用户出现时,从一个cookie中获取用户名,然后从另一个cookie中获取$cookieString。如果$cookieString与存储在DB中的匹配,则验证用户的身份。由于password_hash每次使用不同的盐,所以它与明文是什么无关。