4

我想知道我当前的 BCrypt 实现是否正确,我知道我没有使用BCrypt.checkpw()这可能会导致问题,所以这是我在这里验证它的主要原因。

Hasher.java 容器类:

abstract public class Hasher {
    public static String hash(final char[] input) {   
        String output = Hasher.hash(new String(input));
        for (int i = 0; i < input.length; i++) {
            input[i] = 0;
        }
        return output;
    }

    public static String hash(final String input) {
        return BCrypt.hashpw(input, BCrypt.gensalt());
    }
}

这里有一个问题:出于安全原因JPasswordField给我一个,但只接受字符串。我怎样才能避免那个字符串在我的记忆中漂浮?char[]BCrypt.hashpw()

客户端登录实现:

String hashedPassword = Hasher.hash(password);
Network.getInstance().send("login " + username + " " + hashedPassword);

所以哈希是通过网络发送的,目前网络没有加密,但我计划添加它。

创建帐户的服务器实现:

public static Account createAccount(final String username, final String password) {
    String hashedPassword = Hasher.hash(password.toCharArray());
    return new Account(username, hashedPassword);
}

检查密码的服务器实现:

public boolean checkPassword(final String hashedPassword) {
    return this.hashedPassword.equals(hashedPassword);
}

作为this.hashedPassword服务器内存中的哈希(来自启动时的数据库)。

我的设置的属性:

  • 登录需要客户端大量时间,因为那里的密码是散列的。
  • 创建帐户/更改密码需要服务器大量时间,因为密码随后在服务器上进行哈希处理。
  • 验证登录尝试几乎不需要服务器花费时间,因为不需要进行散列。
  • 如果有人掌握了包含哈希的数据库,那么他将花费大量时间来破解每个帐户的密码。
  • 我仍然需要为BCrypt.gensalt().

请验证我的假设。

问候。

4

1 回答 1

11

这个设置有几个问题。

1)盐应该是在散列过程中随机生成的值(因为它似乎在您的实现中。由于客户端无法访问存储散列的数据库,因此客户端在创建一个时将不知道要使用什么盐登录哈希。

2)这个实现实际上并不是检查客户端传递的密码,而是检查客户端传递的密码哈希。这意味着如果有人获得了您的哈希数据库,他们可以立即使用这些哈希登录。然后不需要破解它们来提取密码,因为您不检查密码。

这两个问题都可以通过移动所有散列服务器端来轻松解决。

更新

关于你提到的问题。

1) 如果您有任何创建安全系统的意图,您应该使用 SSL/TLS。以明文形式发送密码哈希几乎与以明文形式发送密码一样完全不安全。两者都是一个可怕的想法。使用 HTTPS。

2)执行服务器端散列是一种非常普通的做法。散列过程的计算成本高到足以使详尽的搜索变得不切实际,但它不应妨碍您的身份验证工作流程。如果您真的担心被 DoSed,请跟踪给定用户在过去 N 秒内尝试登录的次数。如果他们失败了一定次数,请锁定他们的帐户。

于 2013-05-19T16:44:24.223 回答