对 cookie 进行编码,使其无法被欺骗或读取等 [英] Encoding cookies so they cannot be spoofed or read etc

查看:21
本文介绍了对 cookie 进行编码,使其无法被欺骗或读取等的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写一个 PHP 应用程序.我想将用户登录信息存储在 cookie 中,这样用户就不必在每次访问时都登录.

I am writing a PHP application. I want to store user login information in cookies so user's dont have to log in on every visit.

我想对它们进行编码或混淆,以便它们无法被读取或篡改.

I want to encode them or obfuscate them so that they cannot be read or tampered with.

最好的方法是什么?

更新:

我不会在 cookie 中存储密码,只是一个用户 ID,以便我知道他们是谁,但我希望对其进行编码或加密,以便没有人可以欺骗其他用户

I am not going to be storing passwords in the cookies, simply a user ID so that I know who they are, but I want this to be encoded or encrypted so no one can spoof other users

推荐答案

简答

别这样.从长远来看,你会后悔的.当然,您可以加密它,但是当有人找出您的加密密钥时会发生什么.现在你只是把每个人的证件放在盘子里(嗯,不是真的,但足够接近了).

The short answer

Don't do it. You'll regret it in the long run. Sure, you could encrypt it, but what happens when someone figures out your encryption key. Now you just handed everyones credentials to them on a plate (well, not really, but close enough).

与其存储加密的用户名和密码,为什么不创建一个随机令牌并将其与用户名一起存储?你想要一些相当大的东西,所以像 sha256 散列应该就足够了.

Instead of storing the user-name and password encrypted, why not create a random token and store that with the username? You'd want something sizable, so something like a sha256 hash should suffice.

$randomToken = hash('sha256',uniq_id(mt_rand(), true).uniq_id(mt_rand(), true));

然后,将它与用户一起存储在数据库中,并将 cookie 发送到客户端(我还建议对令牌进行签名以防止篡改:

Then, store it in the db along side the user, and send in a cookie to the client (I'd also suggest signing the token as well to prevent tampering:

$randomToken .= ':'.hash_hmac('md5', $randomToken, $serverKey);

现在,当您验证时,首先检查哈希是否匹配:

Now, when you verify, first check that the hash matches:

list($token, $hmac) = explode(':', $_COOKIE['remember_me'], 2);
if ($hmac != hash_hmac('md5', $token, $serverKey)) {
    die('tampered token!');
}

从那里,只需通过令牌查找用户.如果找到,请登录该用户.

From there, just lookup the user by the token. If you find one, log that user in.

我还建议在每次更改密码时更改令牌.

I'd also suggest changing the token on every single password change.

注意:请勿在实时生产代码中执行此操作.您永远无法完全信任离开您的网络服务器的数据.所以不要那样暴露你的用户信息.这不值得.但是,我确实添加了一些额外的检查(例如对 cookie 进行签名)以使其更安全,但是您已被警告...

Note: do not do this in live, production code. You can never fully trust data that leaves your web-server. So don't expose your user's info like that. It's not worth it. However, I did add some additional checks (such as signing the cookie) to make it somewhat safer, but you have been warned...

要对其进行编码,我将使用 mcrypt 来加密数据进入饼干.然后,我会随机生成一个盐并将其与用户行一起存储,然后使用 hash_hmac<对加密数据进行签名/a> 使用这种独特的盐.这样,如果有人拦截了 cookie 找出了 crypt 的密钥,您仍然可以检测到无效的 hmac,因此您可以找到篡改者.

To encode it, I would use mcrypt to encrypt the data into the cookie. Then, I would make a random salt and store it with the user row, and then sign the encrypted data with hash_hmac using that unique salt. That way, if someone intercepts the cookie and figures out the key to crypt, you can still detect the invalid hmac, so you can find tampers.

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

注意 - 这是伪代码.你需要更多的东西来确保安全(例如检查无效值,确保它成功解密等).

Note - that's pseudo-code. You'll need much more in there to be secure (such as checking for invalid values, making sure it decrypts successfully, etc)..

您应该将会话过期时间保持在尽可能低的时间(我通常使用 30 分钟的会话,但有些网站会更低).过期时间是在最后一次使用之后,所以只要网站被积极使用就没有关系.

You should keep your session expiration as low as practical (I typically use 30 minute sessions, but some sites are lower). The expire time is after the last usage, so as long as the site is being used actively it won't matter.

至于为什么不使用长时间运行的会话,这里有一些缺点:

As far as why not to use a long running session, here are some cons:

  • 磁盘空间 - 每个会话使用相当少量的磁盘空间.但是当你有一个长时间运行的会话时,每个新会话只会增加之前的总数.因此,对于长时间运行的会话,某人只需要使用新的会话 ID 一遍又一遍地访问您的网站,而您的磁盘空间突然不足(假设磁盘正常).

  • Disk space - Each session uses a reasonably small amount of disk space. But when you have a long running session, each new session only adds to the prior total. So with long-running sessions someone just needs to keep visiting your site over and over with a new session id and all of a sudden you're out of disk-space (assuming a sane disk).

文件夹空间 - 每个会话在一个文件夹中包含一个文件.大多数流行的文件系统会因单个文件夹中的大量文件而变慢.因此,如果您放置 100 万个会话文件,则读取或写入会话文件会很慢(非常慢).并且垃圾收集(清理旧文件)将非常非常缓慢(如果它甚至会运行).

Folder space - Each session takes one file in one folder. Most popular filesystems will slow down with a large number of files in a single folder. So if you put 1 million session files, reading or writing to a session file will be slow (very slow). And garbage collection (which cleans old files) will be VERY VERY VERY slow (if it'll even run at all).

会话劫持漏洞被打开.这是因为您在网站上打开的会话越多,猜测有效标识符就越容易(感谢 生日攻击).您安排的会话越少,就越难猜测一个有效的会话.

Session Hijacking vulnerabilities are opened up. This is because the more sessions you have open on the site, the easier it will be to guess a valid identifier (thanks to the birthday attack). The fewer sessions you have laying around, the harder it will be to guess a valid one.

可能还有其他的,但这是一个快速概述.如上所述,不要使用长时间运行的会话,而是使用签名的记住我"令牌.你会过得更好,更安全......

There are likely others, but that's a quick overview. Instead of long-running sessions, use a signed remember-me token as described above. You'll be far better off, and far more secure...

这篇关于对 cookie 进行编码,使其无法被欺骗或读取等的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆