【问题标题】:password_verify failing for password created on another serverpassword_verify 在另一台服务器上创建的密码失败
【发布时间】:2019-03-20 17:02:30
【问题描述】:

我遇到了这样一种情况,即我有两台服务器位于负载平衡器后面。我使用 password_hash() 在一台服务器上生成密码。

基本上是这样的

password_hash('XXXXXXXXX', PASSWORD_DEFAULT);

在我的应用程序中,当我向使用 password_verify() 的端点发出请求时,当请求到达服务器 1 时,密码已正确验证并且请求已验证,但是当负载平衡器将请求发送到服务器 2 时 password_verify( ) 似乎无法验证密码。

我已验证两台服务器都使用完全相同版本的 PHP,在同一天编译并运行 PHP 7.1.2。我这里还有什么遗漏的吗?

【问题讨论】:

  • 旁注:“无法解密密码”_ - password_verify 解密密码。它的散列方式与 password_hash 相同(希望使用相同的盐 - 这可能是您的问题)并进行了省时比较。
  • @Jeff 理解,password_verify 在服务器 2 上返回 false,但在服务器 1 上返回 true
  • 愚蠢的问题:两个 Web 服务器是否使用相同的数据库?
  • 您是否验证函数的输入数据在两种情况下完全相同?
  • 盐不是问题,因为它与哈希一起存储。通过password_hash() 生成的散列独立于服务器。验证哈希所需的一切都在哈希本身中。我能做的唯一区别可能是一个问题,如果创建哈希的服务器是用Argon2i 支持编译的(然后被使用),而另一台服务器没有。如果不是这种情况,那么一定有其他事情发生。

标签: php bcrypt password-hash php-password-hash


【解决方案1】:

好像两台服务器不支持相同的算法,server1可能计算了Argon2 hash,而server2还不知道这个算法。

你可以暂时修复算法,这应该可以解决你的问题,直到两个服务器都理解这两种算法,然后你应该切换回PASSWORD_DEFAULT

password_hash('XXXXXXXXX', PASSWORD_BCRYPT);

【讨论】:

    【解决方案2】:

    在阅读了关于password_hash的更多详细信息后

    http://php.net/manual/en/function.password-hash.php

    string password_hash ( string $password , int $algo [, array $options ] )

    我发现password_hash('XXXXXXXXX', PASSWORD_DEFAULT);的使用

    不能用于负载平衡,至少在没有大量修改函数或滚动你自己的版本的情况下是这样。

    PASSWORD_DEFAULT 输出特定于该实例的哈希密码,除了盐选项在 php7+ 中被贬值之外,并没有真正详细说明它

    $algo 的更多选项(如 Argon2i)直到 php7.2 才添加,因此您需要从 php7.1 升级,因为您目前唯一的选择是使用 bycrypt,成本是唯一的选择。

    http://php.net/manual/en/password.constants.php

    无论哪种方式,即使对于负载平衡 oauth 服务器,这也是一个持续存在的问题。服务器 1 上生成的令牌不适用于服务器 2。 一种解决方法是使用共享缓存和数据库,这违背了将负载平衡到单独硬件甚至不同网络的目的。 另一种选择是在负载均衡器上使用粘性功能。

    绝对要避免的一件事是为您的哈希使用相同的盐来解决此问题。如果您使用相同的数据库,则使用以下散列步骤应该适用于所有服务器。

    使用 CSPRNG 或任何其他生成随机盐的方法生成长随机盐。一个有趣的旁注,硬件/物理随机数生成器,例如 Lavarand。 将盐添加到密码中,并使用标准密码散列函数(如 Argon2i)对其进行散列。 将盐值和哈希值都保存在用户的数据库记录中。

    从数据库中检索用户的盐和哈希。 将盐添加到给定密码并使用相同的散列函数对其进行散列。 将给定密码的哈希值与数据库中的哈希值进行比较。如果它们匹配,则密码正确。否则密码不正确。

    例如---

    <?php
    
    $salt = random_bytes(100);
    
    $password = 'password';
    
    $combined = '$password' + $salt;
    
    
    $hash = password_hash('$combined', PASSWORD_DEFAULT);
    
    if (password_verify('$combined', $hash)) {
    
        echo 'true';
    } else { 
        echo 'no go';
    }
    

    【讨论】:

      猜你喜欢
      • 2010-12-30
      • 2011-02-24
      • 1970-01-01
      • 1970-01-01
      • 2022-06-19
      • 2014-02-18
      • 2016-11-27
      • 1970-01-01
      • 2014-03-13
      相关资源
      最近更新 更多