显然,对用户名和密码进行哈希处理并将其保存为cookie并使用已清理的cookie数据登录对于您的人(或我的网站的安全性)来说不够好。
这种做法是否足够好?
注册程序:
$salt= date('U');
$username= hash('sha256', $salt. $_POST['username']);
$password= hash('sha256', $salt. $_POST['password']);
$token = hash('sha256', $salt. (rand(1,10000000000000000000000000000000000000000000)));
要手动登录,用户输入他们的用户名和密码,它会通过哈希传递并匹配。
成功登录后,将为该用户创建两个厨师。一个持有未使用的用户名,另一个持有哈希令牌。
当用户访问时,如果设置了cookie,则网站会对用户名进行哈希处理,然后使用这两个值进行登录。
这种方法的优点是可以避免将用户密码存储在计算机的任何位置。有人可以破解令牌并访问他们的帐户,但至少我不会危及用户的密码......
回答MySQL real_escape
string and cookies的人说,将用户数据存储在Cookie中是错误的。这会转移问题吗?
答案 0 :(得分:5)
为什么你需要存储密码,甚至是加密版本?您的网站是否在后端使用HTTP Basic auth或其他东西访问第三方API?
不幸的是,你的问题没有明确的答案。 "适当"对不同的人意味着不同的东西。对于安全问题,我不确定它是否足够适当""或者"足够安全。"也就是说,这就是我如何处理登录和密码安全性。在我的数据库users
表中,我有3个与登录相关的列:
username
列是纯文本。 salt
列是一个64个字符的随机选择的字母数字字符串。 passwordHash
列是用户的密码与其salt
值连接在一起,然后不可逆转地进行哈希处理。我使用sha256作为我的哈希。盐是64个字符,因为它是sha256产生的。有一个盐值至少与哈希值一样长,以便在散列字符串中产生足够的可变性。
当用户提交登录表单时,我会对用户名进行数据库查询。如果找不到用户名,我会显示"无效的用户名和/或密码"给用户的错误。如果找到用户名,我将salt与密码连接起来,哈希,看看它是否等于passwordHash
值。如果不是,则向用户显示完全相同的错误。
无论用户名是错误还是密码错误,或两者兼而有之,都能显示完全相同的错误消息。你给黑客的线索越少越好。此外,每当用户更改密码时,我也会给他们一个新的salt
。在那个时间点做这件事真的很容易,并且它使盐值更加清新。
每个用户使用不同盐的系统称为动态salting 。如果黑客尝试使用rainbow tables对您的用户进行反向工程,这会使黑客的工作变得非常复杂。密码。更不用说以不可逆转的形式存储密码对于阻止任何人确定用户密码非常有用,即使他们有权访问数据库和PHP代码。
这也意味着如果您的用户忘记密码,则无法将其恢复。相反,您编写系统只是将其重置为一个随机确定的新值,并将其发送给他们,同时强烈鼓励他们在再次登录时更改密码。您甚至可以编写系统,以便在下次成功登录时强制执行此操作。
我要求密码至少为8个字符。理想情况下,它还应该包括数字和特殊字符,但我还没有决定我应该要求它。也许我应该!
为防止brute-force攻击,我会跟踪前10分钟内所有失败的登录信息。我基于每个IP地址跟踪它们。在3次登录尝试失败后,系统使用sleep()
功能延迟响应进一步的登录尝试。我使用这样的代码块:
$delay = ($failedAttempts - 3);
if ($delay > 0) {
sleep($delay);
}
恕我直言,这比在发生大量失败后锁定用户的帐户要好得多。它减少了您获得的客户支持查询的数量,并且对于那些根本无法记住自己密码的合法用户来说更加优雅。蛮力攻击需要每秒进行多次尝试以获得任何效率,因此在n = x
基础上延迟使他们无法进行任何远程攻击。
使用PHP会话跟踪登录会话。加载网站上的每个网页时,请致电session_start()
。 (如果您有一个共同的header.php
文件,这非常简单。)这使得$_SESSION变量可用。当用户成功登录时,您可以使用它来存储您的站点需要的任何信息,以便知道用户已登录。我通常使用他们的用户ID,用户名,以及可能的特定于该站点的一些其他详细信息。但我不在这里包含密码或哈希值。如果某个黑客进入用户的会话数据(存储在您的服务器上),他们仍然没有机会以这种方式找到用户的密码。
当发生以下两种情况之一时,会发生注销:1)用户的会话cookie被删除,例如通过清除浏览器缓存或有时只是关闭浏览器窗口,或2)您的服务器删除他们的会话数据。当用户按下你的"退出"时,你可以通过调用session_destroy()
来强制执行后者。您网站上的按钮。否则,您可以在一段时间后自动使会话过期。这可能涉及调整session.gc_*
中的php.ini
参数。
如果您在初始登录阶段后必须知道用户的密码,则可以将其存储在$_SESSION
中。这样做只要你的网站需要SSL连接而你已经做到这一点,所以网站在没有网站的情况下无法工作。这样,密码就会被加密,因此会受到packet sniffing的保护。但要知道,如果黑客能够访问您服务器的会话数据,那么这将带来安全风险。
答案 1 :(得分:1)
你的盐不够随意。
这个问题是重播攻击。假设坏人在前往您网站的路上收集用户的cookie。是什么阻止他(坏人)发送相同的值并进入,好像他们是真正的用户一样?
将用户数据存储在cookie中是不好的。你可能会得到的是在用户浏览器的cookie中存储一个随机的64位数字。在应用程序的身份验证数据库中,记录随机数和显着属性,例如用户名,cookie首次生效的时间,到期时间,以及浏览器信息和IP地址信息。
当发送cookie时,您验证它似乎来自与您发送cookie时相同的浏览器。
我没有根据最佳做法或“再次”可靠地识别用户所需的内容进行检查。但是随机数据没有任何意义,所以如果坏人抓住它,它就不是世界末日。捕获的cookie的有效性是有限的,如果您捕获适当的详细信息,坏人必须相当精确地模拟用户的环境。
答案 2 :(得分:0)
为什么要哈希用户名?这并不是秘密,而且您还需要使用未加入(或至少未加保护)的用户名来查找登录凭据。
另外,我认为你会想要使用加密安全的RNG,例如openssl_random_pseudo_bytes()
而不是rand()
。除此之外,基本想法看起来还不错。
答案 3 :(得分:0)
如果我是开放网络上的恶意用户,例如Wi-Fi热点,并希望控制您的某个用户帐户,我可能会尝试以下方法。保卫自己。
您可能考虑的另一种方法是序列化字段,加密该字符串,然后在cookie中存储base64编码的消息。另外,在你现有的盐上添加一些大杂乱的字符串。