“Keep Me Logged in”;-最佳方法

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

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

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

201446 次浏览

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

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

通常我会这样做:

  1. 用户登录时使用“让我继续登录”
  2. 创建会话
  3. 创建一个名为SOMETHING的cookie,包含:md5(salt+username+ip+salt)和一个名为somethingElse的cookie,包含id
  4. 在数据库中存储cookie
  5. 用户做了一些事情并离开----
  6. 用户返回,检查somethingElse cookie,如果它存在,从数据库中获取该用户的旧哈希,检查cookie的内容SOMETHING与数据库中的哈希匹配,这也应该与新计算的哈希匹配(对于ip),因此:cookieHash==databaseHash==md5(salt+username+ip+salt),如果他们做到了,去2,如果他们不去1

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

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

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

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

实现“让我登录”功能意味着您需要准确定义这对用户意味着什么。在最简单的情况下,我将使用它来表示会话有更长的超时:2天(比如说)而不是2小时。为此,您需要自己的会话存储(可能在数据库中),以便为会话数据设置自定义过期时间。然后,你需要确保你设置的cookie可以保留几天(或更长时间),而不是在浏览器关闭时过期。

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

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

我推荐Stefan提到的方法(即遵循改进的持久登录Cookie最佳实践中的指导方针),也建议你确保你的cookie是HttpOnly饼干的,这样它们就不会被潜在的恶意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()还不够强。使用一个库,例如RandomLibrandom_compat,或mcrypt_create_iv() with 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(字符串$name[,字符串$value [, int $expire = 0[,字符串$path[,字符串$domain [, bool 安全的美元 = false [, bool httponly美元 = false]]]]]])

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

定义

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

简单的方法

一个简单的解决方案是:

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

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

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

更好的解决方案

一个更好的解决办法是

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

示例代码

// 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 &铬

enter image description here

优势

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

缺点

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

快速修复

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

多重Cookie方法

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

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

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

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

enter image description here

从上图来看

  • 当前访问的站点是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。

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

  1. 获取cookie数据。删除cookie内的危险字符。用:字符引爆它。
  2. 检查有效性。如果cookie超过X天,则重定向用户到登录页面。
  3. 如果饼干不老;从数据库获取最新的密码更改时间。如果在用户上次登录后更改了密码,则将用户重定向到登录页面。
  4. 如果通行证最近没有变更;获取用户当前的浏览器代理。检查是否(currentUserAgentHash == cookieUserAgentHash)。如果代理相同,转到下一步,否则重定向到登录页面。
  5. 如果所有步骤都成功通过,则授权用户名。

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

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

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

  1. 创建一个表来存储“记住我”数据-分开到用户表,以便我可以从多个设备登录。

  2. 登录成功后(勾选“记住我”):

    a)生成一个唯一的随机字符串作为这台机器上的UserID: bigUserID

    b)生成一个唯一的随机字符串:bigKey

    c)存储cookie: bigUserID:bigKey

    d)在“Remember Me”表中增加一条记录:UserID, IP Address, bigUserID, bigKey

  3. 如果试图访问需要登录的内容:

    a)检查cookie,搜索bigUserID &匹配IP地址的bigKey

    b)如果你发现了,让这个人登录,但在用户表中设置一个“软登录”的标志,这样在任何危险操作时,你都可以提示完全登录

  4. 注销时,将该用户的所有“Remember Me”记录标记为过期。

我能看到的唯一弱点是;

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

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

  • 从来没有存储密码在明文…
  • 从来没有将用户的哈希密码存储在数据库中的多个位置。您的服务器后端总是能够从用户表中提取散列密码。存储冗余数据代替额外的DB事务并不是更有效,相反是正确的。
  • 你的会话ID应该是唯一的,所以没有两个用户可以共享一个ID,因此ID的目的(你的驾驶执照ID号码可以匹配另一个人吗?没有。)这将生成基于2个惟一字符串的两段惟一组合。您的Sessions表应该使用ID作为PK。为了允许多个设备被信任用于自动登录,请使用另一个表来信任设备,其中包含所有经过验证的设备的列表(参见下面的示例),并使用用户名进行映射。
  • 将已知数据散列到cookie中没有任何意义,cookie可以被复制。我们正在寻找的是一个符合要求的用户设备,以提供在攻击者不破坏用户机器的情况下无法获得的真实信息(再次,请参阅我的示例)。然而,这意味着禁止其机器的静态信息(即MAC地址、设备主机名、受浏览器限制的用户代理等)保持一致(或首先欺骗它)的合法用户将无法使用此功能。但如果这是一个问题,考虑一下这样一个事实,即您正在为唯一地标识自己的用户提供自动登录,因此,如果他们拒绝通过欺骗他们的MAC,欺骗他们的用户代理,欺骗/更改他们的主机名,隐藏在代理后面等等来被知道,那么他们是不可识别的,并且永远不应该为自动服务进行身份验证。如果您需要这样做,您需要研究与客户端软件绑定的智能卡访问,该软件为正在使用的设备建立标识。

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

首先,廉价,简单的方式,把一切都推到别人身上。如果你让你的网站支持登录,比如说,你的谷歌+账户,你可能会有一个精简的谷歌+按钮,如果用户已经登录到谷歌,它会让用户登录(我在这里这么做是为了回答这个问题,因为我总是登录到谷歌)。如果您希望用户自动登录(如果他们已经使用受信任和支持的验证器进行了登录),并选中了复选框,那么在加载之前,让您的客户端脚本执行相应的“sign-in with”按钮后面的代码,只需确保服务器在自动登录表中存储一个唯一的ID,其中包含用户名、会话ID和用户使用的验证器。由于这些登录方法使用AJAX,因此无论如何都要等待响应,而该响应要么是已验证的响应,要么是拒绝。如果您得到一个经过验证的响应,就像正常使用它一样,然后像正常一样继续加载登录用户。否则,登录失败,但不要告诉用户,只是继续作为未登录,他们会注意到。这是为了防止窃取cookie(或为了升级权限而伪造它们)的攻击者知道用户自动登录到站点。

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

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

  • 用户'joe'第一次访问网站,会话ID放在cookie ' Session '。
  • 用户'joe'登录,升级特权,获得新的会话ID和更新cookie ' Session '。
  • 用户'joe'选择使用谷歌+自动登录,在cookie 'keepmesignedin'中获得一个唯一的ID。
  • 用户'joe'有谷歌保持他们的签到,允许您的网站自动签到用户使用谷歌在您的后端。
  • 攻击者系统地尝试'keepmesignedin'的唯一id(这是分发给每个用户的公共知识),并且不会登录到其他任何地方;尝试给'joe'的唯一ID。
  • 服务器收到唯一的ID为'joe',拉匹配在数据库谷歌+帐户。
  • 服务器将攻击者发送到登录页面,该页面向谷歌运行AJAX请求以登录。
  • 谷歌服务器接收请求,使用其API查看攻击者当前未登录。
  • 谷歌发送响应称此连接上当前没有登录用户。
  • 攻击者的页面收到响应,脚本自动重定向到登录页面,使用url中编码的POST值。
  • 登录页面获取POST值,将“keepmesignedin”的cookie发送为空值和直到1-1-1970年的有效日期,以阻止自动尝试,导致攻击者的浏览器简单地删除cookie。
  • 攻击者被给予正常的首次登录页面。

无论如何,即使攻击者使用了不存在的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

注意,这个表中没有user字段,因为用户名在登录时是在会话数据中,而程序不允许空数据。session_id和session_token可以使用随机md5哈希值、sha1/128/256哈希值、添加随机字符串的datetime戳来生成,然后哈希,或者任何你想要的东西,但是输出的熵应该保持在可容忍的范围内,以减轻暴力攻击,并且在尝试添加它们之前,应该检查会话类生成的所有哈希值在会话表中是否匹配。

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地址本质上应该是唯一的,因此每个条目都有一个唯一的值是有意义的。另一方面,主机名可以在不同的网络上合法地复制。有多少人使用“Home-PC”作为他们的电脑名称之一?用户名是由服务器后端从会话数据中获取的,因此不可能对其进行操作。对于令牌,应该使用为页面生成会话令牌的相同方法在cookie中为用户自动登录生成令牌。最后,添加了datetime代码,用于用户何时需要重新验证其凭证。要么在用户登录时更新这个datetime,保持它在几天内,要么强制它过期,不管上次登录是什么时候,只保留一个月左右,取决于您的设计要求。

这可以防止有人系统地欺骗他们知道自动登录的用户的MAC和主机名。< em >从不< / em >让用户保留一个cookie与他们的密码,明文或其他。在每个页面导航上重新生成令牌,就像重新生成会话令牌一样。这大大降低了攻击者获取有效令牌cookie并使用它登录的可能性。有些人会说,攻击者可以从受害者那里窃取cookie,并进行会话重放攻击来登录。如果攻击者可以窃取cookie(这是有可能的),他们肯定会破坏整个设备,这意味着他们可以使用设备登录,这就完全违背了窃取cookie的目的。只要您的站点通过HTTPS运行(在处理密码、CC号码或其他登录系统时应该如此),您就已经在浏览器中为用户提供了所有的保护。

有一件事要记住:如果使用自动登录,会话数据应该不会过期。您可以终止错误地继续会话的能力,但是如果会话数据是预计在会话之间继续的持久数据,则验证到系统应该恢复会话数据。如果同时需要持久和非持久会话数据,则使用另一个表作为持久会话数据,并将用户名作为PK,然后让服务器像检索普通会话数据一样检索它,只需使用另一个变量。

一旦以这种方式实现了登录,服务器仍然应该验证会话。这是您可以对被盗或受损系统进行编码的地方;登录会话数据的模式和其他预期结果通常会导致这样的结论:为了获得访问权限,系统被劫持或cookie被伪造。ISS技术人员可以在这里设置规则,触发帐户锁定或自动从自动登录系统中删除用户,使攻击者保持足够长的时间,以便用户确定攻击者是如何成功的以及如何切断他们。

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

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

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

enter image description here

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

我认为你可以这样做:

$cookieString = password_hash($username, PASSWORD_DEFAULT);

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

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