【问题标题】:Unable to validate passwordhash+salt created using php password_hash() using jBcrypt无法验证使用 php password_hash() 使用 jBcrypt 创建的密码哈希 + 盐
【发布时间】:2016-12-26 16:55:45
【问题描述】:

我们正在将身份验证模块从 PHP 迁移到 Java。目前密码 hash+salt 使用 BCrypt 算法存储在数据库中。该值是使用 PHP 的 password_hash() 函数生成的。为了验证纯文本密码,我们使用 PHP 的 password_verify() 函数。

PHP 代码

$hash = password_hash($password,PASSWORD_DEFAULT); //stored in db

if(password_verify($candidate,$hash)===TRUE) { //$hash fetched from DB
    echo "valid";
}

为了将此 auth 模块迁移到 Java,我们通过 jBCrypt-0.4.jar 使用 jBCrypt

Java 代码

private static String hashPassword(String password) {
    String hashed = BCrypt.hashpw(password, BCrypt.gensalt());
    return hashed;
}

private static boolean checkpasword(String candidate, String hashed){
    boolean matches = false;

    if (BCrypt.checkpw(candidate, hashed)){
        matches = true;
    }

    return matches;
}

但是,从 php 生成的 passwordhash+salt 并未在 java 中进行验证。对于字符串 'abcd' ,生成的 hash+salt 是

PHP - $2y$10$SA4iLMAniuNO6p9P1ZJElePaJvlN5eHGZ2dDt2Mutle4FQr1OY4hC

Java - $2a$10$YnqJT5NPCPTI8qKBbLfgIOIOW4eckdbE1R85tJGNRUJKmxz1TLkWG

当我尝试匹配在 Java 中使用 PHP 生成的字符串时

 if (BCrypt.checkpw("abcd", "$2y$10$SA4iLMAniuNO6p9P1ZJElePaJvlN5eHGZ2dDt2Mutle4FQr1OY4hC")){
    matches = true;
} 

我得到了下面的

线程“main”java.lang.IllegalArgumentException 中的异常:无效的盐修订 在 org.mindrot.jbcrypt.BCrypt.hashpw(BCrypt.java:665) 在 org.mindrot.jbcrypt.BCrypt.checkpw(BCrypt.java:764)...`

如何使两者兼容?

【问题讨论】:

    标签: java php hash bcrypt jbcrypt


    【解决方案1】:

    password_hash() 在 PHP 中生成的哈希包含盐。这意味着当您根据纯文本密码检查它时,相同的盐用于针对纯文本密码生成哈希,并且以 恒定时间方式比较两个哈希验证。

    您在 Java 中所做的是每次生成不同的盐,这意味着您无法比较两者。您的 Java 实现使用的是不同的版本,在您的哈希中用 $2a$ 表示。注意 PHP 使用的是 $2y$ 并且盐分明显不同。

    From the PHP manual

    5.3.7 之前的 PHP 版本仅支持“$2a$”作为盐前缀:PHP 5.3.7 引入了新前缀以修复 Blowfish 实现中的安全漏洞。请参阅» this document 了解安全修复的完整详细信息,但总而言之,仅针对 PHP 5.3.7 及更高版本的开发人员应优先使用“$2y$”而不是“$2a$”。

    因此,您不应该在 Java 中生成新哈希来验证由 PHP 生成并存储在数据库中的现有哈希。相反,将存储的哈希提供给BCrypt.checkpasword 进行验证。

    【讨论】:

    • 验证时我没有创建新的哈希。我正在使用数据库中的现有哈希并与用户输入的纯文本进行比较。我已经用我正在使用的确切代码编辑了这个问题。
    • 好的,抱歉,在问题中您包含的代码使您看起来像是在调用hashPassword。在任何情况下,您的 Java 实现都可能不喜欢 $2y$ 标识符。尝试用 Java 中的 $2a$ 替换它,然后再将其发送到 checkpw 并查看是否有效。这不应该破坏任何东西,但如果它确实可以看看这个github.com/codebazz/jbcrypt
    猜你喜欢
    • 1970-01-01
    • 2015-08-22
    • 1970-01-01
    • 2011-11-27
    • 2022-06-13
    • 2017-01-31
    • 2021-07-30
    • 1970-01-01
    • 2014-12-03
    相关资源
    最近更新 更多