我正在编写一个PHP应用程序。我想将用户登录信息存储在cookie中,这样用户就不必在每次访问时都登录。
我想对它们进行编码或对它们进行模糊处理,以便它们无法被读取或篡改。
这样做的最佳方式是什么?
更新
我不打算在密码中存储密码,只是一个用户ID,以便我知道他们是谁,但我希望对其进行编码或加密,以免任何人欺骗其他用户
答案 0 :(得分:52)
不要这样做。从长远来看,你会后悔的。当然,你可以加密它,但是当有人找出你的加密密钥时会发生什么。现在你只需将每个人的凭据交给他们(好吧,不是真的,但足够接近)。
为什么不创建随机令牌并使用用户名存储,而不是加密存储的用户名和密码?你想要一些相当大的东西,所以类似sha256
哈希就足够了。
$randomToken = hash('sha256',uniq_id(mt_rand(), true).uniq_id(mt_rand(), true));
然后,将其存储在用户旁边的数据库中,并将cookie发送给客户端(我还建议签署令牌以防止篡改:
$randomToken .= ':'.hash_hmac('md5', $randomToken, $serverKey);
现在,当您验证时,首先检查哈希是否匹配:
list($token, $hmac) = explode(':', $_COOKIE['remember_me'], 2);
if ($hmac != hash_hmac('md5', $token, $serverKey)) {
die('tampered token!');
}
从那里,只需通过令牌查找用户。如果找到,请将该用户登录。
我还建议在每次更改密码时更改令牌。
注意:不要在实时生产代码中执行此操作。您永远不能完全信任离开Web服务器的数据。所以不要暴露你的用户信息。这不值得。但是,我确实添加了一些额外的检查(例如签署cookie)以使其更安全一些,但是你已被警告......
要对其进行编码,我会使用mcrypt
将数据加密到cookie中。然后,我会创建一个随机盐并将其与用户行一起存储,然后使用该唯一盐用hash_hmac
对加密数据进行签名。这样,如果有人截获cookie 和找出了crypt的密钥,你仍然可以检测到无效的hmac,这样你就可以找到篡改。
function generateCredentialsCookie($user_id, $password) {
$encrypted = encrypt($user_id.':'.$password, $secretkey);
$salt = uniq_id(mt_rand(), true);
$encrypted .= ':'.hash_hmac('sha256', $encrypted, $salt);
storeSaltForUser($user_id, $salt);
set_cookie('credentials', $encrypted);
}
function readCredentialsCookie() {
$parts = explode(':', $_COOKIE['credentials']);
$salt = array_pop($parts);
$encrypted = implode(':', $parts); //needed incase mcrypt added `:`
$raw = decrypt($encrypted, $secretkey);
list ($user_id, $password) = explode(':', $raw, 2);
if ($salt == getSaltForUser($user_id))
return array($user_id, $password);
} else {
return die('Invalid Cookie Found');
}
}
注意 - 这是伪代码。你需要更多安全(例如检查无效值,确保成功解密等)。
您应该将会话过期保持在尽可能低的水平(我通常使用30分钟的会话,但有些网站会更低)。到期时间是在最后一次使用之后,因此只要站点被主动使用就无所谓了。
至于为什么不使用长时间运行的会话,这里有一些缺点:
磁盘空间 - 每个会话使用相当少的磁盘空间。但是当你有一个长时间运行的会话时,每个新会话只会增加到之前的总数。因此,对于长时间运行的会话,有人只需要使用新的会话ID一遍又一遍地访问您的站点,并且突然间您没有磁盘空间(假设一个理智的磁盘)。
文件夹空间 - 每个会话在一个文件夹中占用一个文件。大多数流行的文件系统会因单个文件夹中的大量文件而变慢。因此,如果您放置100万个会话文件,读取或写入会话文件将会很慢(非常慢)。垃圾收集(清理旧文件)非常非常慢(如果它甚至可以运行)。
Session Hijacking个漏洞被打开了。这是因为您在网站上打开的会话越多,就越容易猜到有效的标识符(感谢the birthday attack)。您铺设的会话越少,猜测有效会话就越难。
可能有其他人,但这是一个快速概述。如上所述,使用签名的remember-me令牌而不是长时间运行的会话。你会好得多,而且更安全......
答案 1 :(得分:4)
将用户数据存储在cookie中是错误的方法。您应该使用PHP Sessions。将存储在客户端上的唯一内容将是简单cookie中的会话ID(PHP将自动为您处理)。它已经是一个加密的字符串。
PHP将跟踪服务器端的用户数据。
这将实现您所描述的预期效果,同时比使用Cookie更安全。
答案 2 :(得分:2)
绝对不能在任何情况下将用户凭据存储在cookie中。您应该始终假设cookie,因为所有用户输入都不可信任。
几种方法:
如果用户选择“记住我”,则只需在初始化会话之前设置以下内容。
session_set_cookie_params(60 * 60 * 24 * 7); //save cookie session for 7 days
否则,在数据库中存储唯一标记,并查询该标记以查看它是否属于用户,如果是,则填充其会话。
我会推荐第一个选项。
答案 3 :(得分:0)
保存前加盐饼干。添加用户代理,ip以扩展安全性。
$cookie_to_save = sha1($pwd . $user_agent . $yourSalt);
自动登录
if($cookie_saved == sha1($pwd . $user_agent . $yourSalt) ok...
答案 4 :(得分:0)
生成16个或更长的加密安全随机数并将其存储在cookie中更为简单。无需加密/解密。 使用它在服务器端检查有限的有效时间(不要依赖于MaxAge或Expires)。这是一个会话cookie。
这非常安全,因为没有关键信息离开服务器。
此技术的缺点是您需要为该会话ID创建数据库索引,并为每个请求执行数据库查找。对于大多数网站而言,这可能已经足够好了,只要延迟不可察觉且服务器负载可接受。
为了最大限度地减少服务器负载和响应延迟,将用户ID,角色和cookie创建标记存储在安全cookie值中是一个有效选项。不需要数据库或缓存命中来清除无效请求,如果用户ID是压缩的,则索引会很小并且查找速度更快。但除非你知道自己在做什么,否则不要发明自己的安全值编码。
这种方法的缺点是,如果有人发现了密钥,他就可以伪造cookie。然后,他可以创建具有不同用户ID的cookie并访问其帐户。因此,在风险有限且对密钥的访问受到控制的情况下使用此方法。执行加密/解密和隐藏密钥的专用硬件设备可能是一种解决方案。但这种情况目前并不常见且昂贵。它的延迟可能比在缓存中查找随机会话ID更大。后者是更简单,更安全的解决方案。
使用公钥/私钥来保护cookie中的值,可用于保护私钥。但要做到这一点要复杂得多,延迟可能与具有简单随机缓存会话ID的系统相当。
另请注意,使用Cookie的任何方法都需要使用HTTPS。否则,中间人或间谍交换数据的人可以轻松获得cookie的副本并冒充用户。