这个用户认证安全吗?

3
我正在尝试停止使用md5()来存储和比较密码。因此,我想开始使用password_hash()。
以前我是这样做的,我会在他们的会话或cookie中存储用户名和密码的md5值(如果他们选择了“记住我”),然后检查数据库是否存在任何用户与该用户名和md5的密码匹配。我意识到这不太安全,这就是为什么我想停止这个做法。
现在我不能再这样做了,因为password_hash()总是改变的,所以我不能在他们的会话中存储哈希值,然后在数据库中检查它,因为我需要对未哈希的密码使用password_verify()。
我的问题是,如果我在用户表中成功登录时存储一个哈希的“会话ID”和“令牌”,然后将其与用户ID一起存储在其会话/cookie中以便进行数据库检查,这样安全吗?当我说哈希的“会话ID”和“令牌”时,我指的是随机大数字的sha256或甚至md5哈希...
示例:
用户登录->在用户的cookie/session中存储哈希的“会话ID”和“令牌”,并更新他们在数据库中的行,使其包含哈希的“会话ID”和“令牌”。
用户访问网站->代码检查他们的浏览器会话/cookie变量是否存在于数据库中的“会话ID”和“令牌”。如果是,则假定找到的行代表当前用户。
任何见解都将不胜感激。

您可以使用盐值密码哈希。 - Praveen D
2
@PraveenD - password_hash() 已经生成了带盐的哈希值.... 你实际上在建议什么? - Mark Baker
@PraveenD - password_hash() 生成一个带有随机盐的哈希值,每个哈希值的盐都是不同的...... OP 已经知道这一点了,也许你可以解释一下你的意思。 - Mark Baker
即使使用第三个参数,password_hash() 也会生成随机哈希码。例如 $salts = [ 'salt' => 12, ]; password_hash("password", PASSWORD_BCRYPT, $salts) - Kirs Sudh
1
静态盐完全抵消了使用password_hash的效果。如果我要这样做,我可能会坚持使用md5()。 - inkd
显示剩余4条评论
2个回答

1
当用户登录时,我会使用uinqid()(http://php.net/uniqid)为他的登录生成一个唯一的ID,并将其存储在一个新表中。然后检查此表以查看cookie是否与存储在表中的唯一ID匹配。
您必须确保在用户再次登录时删除表行,但如果用户在多个设备上设置了“记住我”,这将导致问题,因此我会为每个ID在表中设置一个过期日期,并且登录脚本将:
  1. SELECT * FROM 'UNIQIDS' WHERE $current_date_and_time > 'EXPIRE' and delete all results
  2. 检查cookie是否存在。 如果有并且与唯一ID匹配,则在计算机上创建会话,否则显示登录页面
用户登录后:
  1. 检查表中是否已经存储了唯一标识符
  2. 如果已存在一个唯一标识符,检查当前日期和时间是否已过期,如果已过期则删除该行
  3. 如果唯一标识符已过期,则生成一个新的唯一标识符,并将其过期日期与您正在生成的cookie的过期日期匹配。如果唯一标识符尚未过期,则计算现在和它过期之间的时间,并创建一个包含其值并在计算出的时间内过期的cookie。

这是非常安全的,因为很难伪造此cookie,并且它不会将用户密码信息传递到客户端机器。

为了更安全,您可以对生成的唯一标识符进行md5加密,但实际上没有必要,因为它不包含任何重要信息。

这可能有些复杂,但如果您逐步进行,应该不难理解。

祝你好运!


令牌在存储到数据库之前应进行哈希处理,否则具有对db(SQL注入)的读取权限的攻击者可以读取令牌并冒充用户。由于令牌(20个以上的随机字符)是一个非常强大的“密码”,因此可以使用像SHA-256这样的快速无盐散列来使它们可比较。 - martinstoeckli
不一定。如果您从表中选择所有行,不让最终用户访问SQL语句,创建一个assoc并使用for/loop让php搜索assoc,而不是让mysql在返回assoc之前搜索表,那么它将使表免受SQL注入攻击。之后,如果您的SQL被黑客攻击,那么您面临的问题比哈希安全性更大。 - zachal
并不一定需要查询包含令牌的表格来揭示哈希值,每个SQL语句都必须得到保护。请查看我的教程中的示例。如果您使用第三方库,您也需要测试此代码。即使如此,令牌丢失的其他方式仍然存在,例如废弃的服务器、备份等。 - martinstoeckli
非常抱歉,您是正确的。为了安全起见,uniqids 应该进行哈希处理,以及任何其他可能敏感的信息,但是还应该注意防范 SQL 注入攻击,因为任何决心的黑客都可以在足够的时间内破解哈希。此外,请确保您的 uniqids 和 cookies 经常过期,以防止有人通过反复创建具有不同值的虚假 cookie 来暴力破解您的系统。 - zachal

0

为了得到最佳的密码哈希和使用方法,同时编写简单的代码,以下是一个示例...

$salts = ['cost' => 12]; password_hash("Password", PASSWORD_BCRYPT, $options);

$salts 是一个数组,在调用 password_hash() 时多次组合使用。

PASSWORD_BCRYPT 是一种算法,它使用 "$2y$" 标识符和 Blowfish 加密算法来哈希字符串。这将输出 60 个字符的混乱集合。


您可以在$salts中添加任意数量的键值对。 - Kirs Sudh
1
请不要使用 ['salt' => 12],正确的应该是 ['cost' => 12] - Scott Arciszewski
没错,@Scott Arciszewski,我后来意识到了。使用['cost' => 12] - Kirs Sudh
这并没有解决原帖作者的问题。虽然对于密码哈希来说是正确的,但问题是关于如何存储会话令牌,其哈希必须是可搜索的且不能包含随机盐。 - martinstoeckli

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接