我正在尝试为有关 Cookie/会话和数据库数据的问题找到一个安全的解决方案。
我已经阅读了不同的文章,例如解释不同 Cookie 盗窃和会话固定方法的 http://www.devshed.com/c/a/PHP/Sessions-and-Cookies/,以了解我将面临的安全问题。
问题如下:我有数据库表,其中存储了使用 AES_ENTRYPT()
输入的数据,使用用户密码对其进行加密。这意味着,即使要阅读信息,我也必须使用明文密码来解密数据。
如果我只将密码存储在 $_SESSION
变量中,这可能不是问题,但这会拒绝在多天内通过 cookie 保持登录的能力。
换句话说,我必须将明文密码存储在cookie中(至少,使该功能保持登录状态)
现在,您可以使用加盐的MD5()或SHA-256()哈希作为标识符,而不是密码。但是我无法使用哈希值解密数据。这意味着我必须将密码服务器端存储在数据库中?或者有其他安全的方法吗?),将其连接到标识符 - 但是密码对于有权访问数据库的每个人都可以访问,并且可以直接解密那里的数据。
有没有一种安全的方法,连接我存储在cookie中的标识符,并将其连接到服务器存储的用户输入(密码/帐户名),这实际上使可以访问数据库的人有可能读取服务器端存储的用户输入?
要求是,即使在最坏的情况下,有人转储了数据库和cookie(但无法访问服务器RAM),该人也不应该能够访问用户密码并使用它解密存储的数据。
为避免混淆,请回顾一下:
这不是用户识别问题 - 登录过程单独发生(通过通常的方式:密码/登录数据的md5()哈希)。我的问题是,用户数据(如地址,姓名,电子邮件)使用用户密码进行加密。所以我需要登录名的密码来解密它们。如果用户只是登录,这没有问题,因为我在 $_POST 数据中有密码,并且可以使用它。但是登录后呢?一旦 _POST 美元或 _SESSION 美元消失,我就无法再次解密数据。
可能的解决方案
经过一些输入,我可能会想出一种方法 - 它不是完全安全的,但它应该足够好用:
(这与登录/用户身份验证过程是分开的,我只指加密/密钥部分)
user registers OR changes password:
generate a new hash out of $email and $password => $auth
do NOT store $auth in the usertable, just keep it
generate a new random key for the user => $key (only on registering, not on pw change)
encrypt $key with $auth, storing it into the usertable
encrypt all user data with $key
user logs in (or after registering / password change):
generate $auth ($password + $email)
set cookie with $auth as variable
user is logged in (cookie / session / after login):
decrypt $key with $auth
use $key for data encryption / decryption (serverside)
这里唯一的问题是,如果有人可以得到$auth,他们可以解密$key,然后解密数据。我正在考虑为每次登录生成一个新$auth,但这会引发一个问题,如果旧$auth丢失,我如何解密密钥。这和令牌之间的区别在于,这增加了另一层,其中令牌不是加密密钥本身。无论如何,我认为解决方案是除了公钥/私钥之外最接近我想要的。谢谢。
关键是找到一种方法,将一条信息存储在cookie中,将一条信息存储在数据库中,这些信息一起获得明文密码,但单独是无用的。
我能想到的最好的方法是创建一个类似于@fire建议的随机令牌:
$token = md5(uniqid(mt_rand(), true));`
然后使用此令牌加密密码并将加密的密码与userid
一起存储在cookie中,以便您知道此加密部分的用途。
当客户端返回时,可以使用 cookie 通过id
检索数据库行,您可以从数据库中提取令牌来解密 cookie 信息以获取明文密码。这样,如果有人破解了cookie,他们就会获得一个加密的密码;如果他们进入数据库,他们会获得解锁密码的密钥,但没有加密的密码。
在用户表中有一个名为 token
的字段,当您第一次插入用户时,它可以是随机哈希...
$token = md5(uniqid(mt_rand(), true));
然后将用户 ID 和令牌存储在 Cookie 中,您可以使用它们来查找用户。
据我了解您的要求,您不能在客户端或服务器端存储密码。因此,您根本无法存储它。让用户为每次页面加载输入密码。
您可以使用例如memcached或APC将内容存储在RAM中,或者通过创建自己的软件,您可以在服务器上进行通信。这不会给你带来太多增强的安全性,因为任何有权访问服务器(通过shell)的人都可以以与您的软件完全相同的方式要求密码。在我看来,它破坏了"无文件,无数据库"要求的大部分目的,但它可能是您的解决方案。
保持用户登录
使用简单的令牌系统,将令牌存储在用户数据库中和cookie用户端。如果您需要更多信息,我建议您使用谷歌(这很简单)
对于纯文本密码
您可以使用多种方法将其存储在RAM中,这是memcache的示例
$memcache->set($token, $password);
然后,使用以下方法从 RAM 中检索信息:
$user_password = $memcache->get($_COOKIE['token']);
有几种解决方案可以使用PHP在RAM中存储数据:Memcache和APC(用户缓存部分)