Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java: Is this good use of BCrypt?

I would like to know if my current implementation of BCrypt is correct, I am aware that I am not using BCrypt.checkpw() which may lead to an issue so that is the main reason I verify it here.

Hasher.java container class:

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());
    }
}

One concern here: JPasswordField gives me a char[] for security reasons, however BCrypt.hashpw() only accepts Strings. How can I avoid that String from floating around in my memory?

The client implementation of logging in:

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

So the hash gets sent over the network, currently the network is not encrypted but I plan on adding that.

The server implementation on account creation:

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

The server implementation of checking password:

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

With this.hashedPassword being the hash that is in the server's memory (which comes from a database on bootup).

Properties of my setup:

  • Logging in takes the client significant time, as the password is hashed there.
  • Creating an account/Changing password takes the server significant time, as the password is hashed on the server then.
  • Validating login attempts takes the server practically no time, as no hashing needs to be done.
  • If someone gets hold of the database containing the hashes, then it will take him significant time to crack the password per account.
  • I still need to figure out a good work factor for the BCrypt.gensalt().

Please verify my assumptions.

Regards.

like image 871
skiwi Avatar asked Dec 21 '22 05:12

skiwi


1 Answers

There are a couple problems with this setup.

1) The salt should be a value randomly generated during the hashing process (as it seems to be in your implementation. Since the client does not have access to the database of stored hashes, the client will not know what salt to use when creating a login hash.

2) This implementation is not actually checking the password passed by the client, it's checking the password hash passed by the client. That means that if someone gets your database of hashes, they can immediately use those hashes to login. Then do not need to crack them to extract passwords, since you do not check the passwords.

Both these issues can be easily solved by moving all hashing server side.

Update

Regarding the issues you mentioned.

1) If you have any intention of creating a secure system, you should be using SSL/TLS. Sending password hashes in the clear is almost as totally insecure as sending passwords in the clear. Both are a terrible idea. Use HTTPS.

2) Performing server side hashing is a pretty ordinary practice. The hashing process is computationally expensive enough to make exhaustive search impractical, but it shouldn't hinder your authentication workflow. If you're really concerned about being DoSed, keep track of how many times a given user has tried to login in the last N seconds. If they've failed a certain number of times, lock their account.

like image 82
Aurand Avatar answered Jan 01 '23 17:01

Aurand