gpt4 book ai didi

php - "Keep Me Logged In"- 最好的方法

转载 作者:IT老高 更新时间:2023-10-28 11:38:40 27 4
gpt4 key购买 nike

我的网络应用程序使用 session 来存储用户登录后的信息,并在用户在应用程序内从一个页面到另一个页面时维护这些信息。在这个特定的应用程序中,我存储了此人的 user_idfirst_namelast_name

我想在登录时提供一个“让我保持登录”选项,它将在用户的计算机上放置一个 cookie 两周,当他们返回应用程序时,它将以相同的详细信息重新启动他们的 session 。

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

最佳答案

好的,让我直截了本地说:如果您为此目的将用户数据或从用户数据派生的任何内容放入 cookie,那么您做错了什么。

那里。我说了。现在我们可以继续讨论实际的答案了。

您问,散列用户数据有什么问题?嗯,它归结为暴露表面和通过默默无闻的安全性。

想象一下你是一个攻击者。您会在 session 中看到为 remember-me 设置的加密 cookie。它有 32 个字符宽。哎呀。那可能是 MD5...

让我们也想象一下,他们知道您使用的算法。例如:

md5(salt+username+ip+salt)

现在,攻击者需要做的就是暴力破解“盐”(这实际上不是盐,但稍后会详细介绍),他现在可以使用任何用户名生成他想要的所有假 token IP地址!但是暴力破解盐很难,对吧?绝对地。但现代 GPU 非常擅长它。除非您在其中使用足够的随机性(使其足够大),否则它会迅速折叠,并随之掉落您城堡的 key 。

简而言之,保护你的唯一东西就是盐,它并没有你想象的那样真正保护你。

等一下!

所有这些都假设攻击者知道算法!如果它是 secret 和令人困惑的,那么你是安全的,对吧? 错误。这种思路有一个名字:Security Through Obscurity,应该绝不依赖它。

更好的方法

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

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

如果攻击者猜到另一个用户的随机 token 怎么办?

好吧,让我们在这里做一些数学运算。我们正在生成一个 128 位随机 token 。这意味着有:

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

所以每秒有 50 万亿次猜测。真快!对吧?

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 六亿秒...

让我们试着把它归结为更友好的数字。

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);
}
}
}

注意:不要使用 token 或用户和 token 的组合来查找数据库中的记录。始终确保根据用户获取记录,然后使用时间安全比较功能来比较获取的 token 。 More about timing attacks .

现在,SECRET_KEY 是一个密码 secret (由 /dev/urandom 之类的东西生成和/或派生自高熵输入)。此外,GenerateRandomToken() 需要是强随机源(mt_rand() 还不够强。使用库,例如​​ RandomLibrandom_compat ,或 mcrypt_create_iv()DEV_URANDOM)...

hash_equals()是为了防止timing attacks .如果您使用低于 PHP 5.6 的 PHP 版本,函数 hash_equals()不支持。在这种情况下,您可以替换 hash_equals()使用timingSafeCompare函数:

/**
* 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;
}

关于php - "Keep Me Logged In"- 最好的方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1354999/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com