【问题标题】:PHP Forgot Password FunctionPHP忘记密码功能
【发布时间】:2011-09-28 23:06:58
【问题描述】:

我有一个小型社区网站,我需要实现某种忘记密码功能。我目前将密码存储在数据库中,使用MD5 加密。

是否可以“解密”并通过电子邮件将其发送给用户,或者我需要一个密码重置页面?

【问题讨论】:

  • 存储密码 MD5 编码的整个想法是您无法解码它们。即使有人闯入您的系统并转储数据库,他们也无法获得密码(当然,除非密码太弱,但那是另一回事了......)

标签: php security md5 password-recovery


【解决方案1】:

使用php内置的password_verify和password_hash。

【讨论】:

    【解决方案2】:

    正如 Marcus Reed 所说,在 2015/2016 年,如果您的 PHP 版本 >=5.5,请不要使用 MD5,password_hash() 和 password_verify() 为您的密码提供简单安全的散列,并能够提供成本和自动加盐。

    我目前无法投票或发表评论,因此我提供明确的声明以避免混淆。

    【讨论】:

      【解决方案3】:

      根据这篇文章The definitive guide to forms based website authentication,对于第 3 步和第 4 步,我不确定您是否应该发送与您存储的相同的令牌。

      我猜您必须发送令牌,然后对其进行哈希处理并将哈希处理后的令牌存储在数据库中。否则,如果您的数据库遭到破坏,则可以访问重置密码页面。

      总结一下:

      $token = md5(microtime (TRUE)*100000);
      $tokenToSendInMail = $token;
      $tokenToStoreInDB = hash($token);
      

      其中 hash 是一种散列算法。

      【讨论】:

      • 这是一个非常好的点,将散列令牌存储在数据库中。 +1
      • 虽然使用可预测的令牌不是一个好主意...它不应该基于任何可预测的东西,比如时间。 (这将允许攻击者遍历生成令牌时的值)在 PHP7 中,应该使用random_bytes。在 PHP5 上,应该使用兼容性实现或openssl_random_pseudo_byte
      • (另一种选择是使用秘密随机字符串的散列和用户的详细信息,并希望得到一些不错的随机数据。由于它存储在数据库中,因此没有理由将令牌存储在可预测的)(使用此方法,我将在长字符串上使用password_hash 生成令牌,并在链接中发送哈希的base64 编码版本)。 (在存储到数据库之前再次对其进行哈希处理也可能是一种选择,但在 4-24 小时后使重置链接失效可能是更好的防御措施)(使用适当的随机数据,只需发送经过 base64 编码的数据库就可以了)跨度>
      【解决方案4】:

      最好的办法是要求人们在注册时提交他们的电子邮件地址。然后,如果他们忘记了,有一个忘记密码链接,该链接使用一个随机值重置他们的密码,该值通过电子邮件发送给他们,这样他们就可以获得访问权限,然后将他们的密码改回更容易记住的密码。这样您就不需要损害安全性。 你可以有一个链接,他们只需要提交他们的用户名,但为了更好的安全性,你应该有一个问题和答案或令人难忘的单词。

      【讨论】:

        【解决方案5】:

        编写一个接受 md5 和电子邮件地址作为获取参数的页面,并在数据库中查找电子邮件和 md5 密码。按照 Jared Cobb 的说明,这应该会让你走上正确的道路。我也只是添加了一些示例

        例如 url 发送http://yourdomain.com/resetpassword.php?code=md5codesentviaemail

         $code = isset($_GET['code']) ? $_GET['code'] : '';
            $email = isset($_GET['email']) ? $_GET['email'] : '';
        $checkPw = '';
        
            if(empty($code) || empty($email))
            {
             die();
            }
            $sqlQuery = 'SELECT * FROM users WHERE email = "'.$email.'";
        //remember to check for sql injections
            //then get the results as an array, i use a database class eg $user
        
            if(!empty($user['password']))
            {
             $checkPw = md5($user['password']);
            }else
            {
             die();
            }
        
            if($checkPw !== $code)
            {
             die();
            }else
            {
            //display form for user to change password
            }
        

        这应该足以让您知道用户是有效用户并更改他的密码

        【讨论】:

          【解决方案6】:

          MD5 散列密码不可逆。 (MD5 是散列,而不是真正的加密,所以有一个细微的差别)。而且是的您肯定会希望提供密码“重置”过程(而不仅仅是通过电子邮件发送密码)。

          为您提供安全密码重置的高级工作流程...

          1. 当用户要求重置密码时,让他们输入他们的电子邮件地址
          2. 不要指明该电子邮件地址是否有效(只需告诉他们已发送一封电子邮件)。这是有争议的,因为它降低了可用性(即我不知道我注册了哪封电子邮件),但它为试图收集有关哪些电子邮件实际在您的网站上注册的信息的人提供的信息较少。
          3. 生成一个令牌(可能用盐散列时间戳)并将其存储到数据库中的用户记录中。
          4. 向用户发送一封电子邮件以及指向您的 https 重置页面的链接(网址中的令牌和电子邮件地址)。
          5. 使用令牌和电子邮件地址验证用户。
          6. 让他们选择一个新密码,替换旧密码。
          7. 此外,最好在特定时间范围(通常为 24 小时)后使这些令牌过期。
          8. (可选)记录发生了多少“忘记”尝试,并在人们请求大量电子邮件时实施更复杂的功能。
          9. (可选)记录(在单独的表中)请求重置的个人的 IP 地址。从该 IP 增加计数。如果它超过了,比如说,10...忽略他们未来的请求。

          让您更详细地了解散列...

          当您在 PHP 中使用 md5() 函数对密码之类的值进行哈希处理时,无论您在哪个服务器上运行该密码,该密码的最终值都将是相同的。 (所以我们可以立即看到散列和加密之间的一个区别......不涉及私钥/公钥)。

          所以在这里你会看到人们提到rainbow tables 的漏洞。彩虹表的一个非常基本的解释是......您 md5() 散列一堆字典单词(弱密码)以获得它们的 md5() 散列值。将它们放在数据库表(彩虹表)中。

          现在,如果您破坏了网站的数据库,您可以针对您的彩虹表运行用户的散列密码,以(实质上)将散列“反转”回密码。 (你并没有真正“反转”哈希......但你明白了)。

          这就是“加盐”密码的最佳做法。这意味着(再次,这里是非常基本的想法)您将随机值附加到用户的密码散列之前。现在,当彩虹表针对您的数据库运行时,它并不那么容易“反转”,因为“password”的 md5() 哈希与“password384746”不同。

          这是一个不错的 SO Q/A,应该会有所帮助。 Secure hash and salt for PHP passwords

          【讨论】:

          • @Jared Cobb:8 到底是什么意思?
          • @testing 好问题...与第 9 点非常相似,除了在这种情况下,攻击者使用僵尸网络、代理或其他循环方法从不同的 IP 地址攻击您时间。例如,如果您的系统检测到“忘记请求”在几分钟或几小时内发生大量增加,您可能会考虑暂时减慢或禁用该功能。 (当然,您的阈值将由您自己对用户群规模和“正常”数量的主观判断决定)。
          • @JaredCobb #7 我通常在他们重置密码后立即生成新令牌,所以下次他必须使用新令牌重置密码。
          • 我可以使用以前用户的密码(经过哈希处理并存储到数据库中)作为随机令牌(用于第三步)吗?实际上,我需要将其作为该 reset-url 的参数传递。我可以这样做吗?
          • @Thoaren 在我看来,强制他们提交用户名是可选的。我认为它不会提供任何额外的安全性。如果有人(以欺诈方式)从用户的电子邮件帐户中获得了链接,他们可能已经在 your 网站上入侵了该帐户。如果用户的电子邮件地址他们的用户名,那么这将是一个有争议的问题。
          【解决方案7】:

          MD5 是单向函数。你不能解密它。所以你需要有一个密码重置页面。

          【讨论】:

            【解决方案8】:

            您无法解密密码,甚至不应该考虑通过明文向用户发送密码。 (这是让我永远不再使用网站的#1 方法;这是一个巨大的安全漏洞。)提供一个密码重置页面,该页面由包含时间相关密钥的链接触发,该密钥发送到用户的密码恢复电子邮件;这是密码恢复领域的最新技术。

            【讨论】:

              【解决方案9】:

              不,MD5 是不可逆的。对密码进行哈希处理的目的是为了让访问您的数据库的攻击者无法访问每个人的密码。

              也就是说,MD5(尤其是未加盐的 MD5)通常可以使用rainbow table 进行攻击。为了安全起见,您最好使用bcrypt

              【讨论】:

                【解决方案10】:

                您需要进行密码重置页面。 PHP没有办法解密MD5。

                【讨论】:

                  【解决方案11】:

                  不,你不能解密它。这就是整个想法。

                  您需要向他们发送临时密码并让他们重置。

                  【讨论】:

                    【解决方案12】:

                    MD5 旨在成为一种单向哈希。您需要让他们重置密码。

                    【讨论】:

                      猜你喜欢
                      • 2013-12-09
                      • 2011-10-19
                      • 1970-01-01
                      • 2017-07-06
                      • 2012-02-22
                      • 2013-10-12
                      • 2013-12-01
                      • 1970-01-01
                      • 2010-10-06
                      相关资源
                      最近更新 更多