2

我们正在将我们的身份验证模块从 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";
}

为了将此身份验证模块迁移到 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;
} 

我得到了以下

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

如何使两者兼容?

4

1 回答 1

1

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

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

来自 PHP 手册

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

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

于 2016-08-19T14:02:43.720 回答