どうすればJavaでパスワードをハッシュできますか?java


Answers

ここでは、2つのメソッドが完全に実装されています。

String getSaltedHash(String password)
boolean checkPassword(String password, String stored)

要点は、攻撃者がデータベースとソースコードの両方にアクセスしても、パスワードはまだ安全だということです。

import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import java.security.SecureRandom;
import org.apache.commons.codec.binary.Base64;

public class Password {
    // The higher the number of iterations the more 
    // expensive computing the hash is for us and
    // also for an attacker.
    private static final int iterations = 20*1000;
    private static final int saltLen = 32;
    private static final int desiredKeyLen = 256;

    /** Computes a salted PBKDF2 hash of given plaintext password
        suitable for storing in a database. 
        Empty passwords are not supported. */
    public static String getSaltedHash(String password) throws Exception {
        byte[] salt = SecureRandom.getInstance("SHA1PRNG").generateSeed(saltLen);
        // store the salt with the password
        return Base64.encodeBase64String(salt) + "$" + hash(password, salt);
    }

    /** Checks whether given plaintext password corresponds 
        to a stored salted hash of the password. */
    public static boolean check(String password, String stored) throws Exception{
        String[] saltAndPass = stored.split("\\$");
        if (saltAndPass.length != 2) {
            throw new IllegalStateException(
                "The stored password have the form 'salt$hash'");
        }
        String hashOfInput = hash(password, Base64.decodeBase64(saltAndPass[0]));
        return hashOfInput.equals(saltAndPass[1]);
    }

    // using PBKDF2 from Sun, an alternative is https://github.com/wg/scrypt
    // cf. http://www.unlimitednovelty.com/2012/03/dont-use-bcrypt.html
    private static String hash(String password, byte[] salt) throws Exception {
        if (password == null || password.length() == 0)
            throw new IllegalArgumentException("Empty passwords are not supported.");
        SecretKeyFactory f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
        SecretKey key = f.generateSecret(new PBEKeySpec(
            password.toCharArray(), salt, iterations, desiredKeyLen)
        );
        return Base64.encodeBase64String(key.getEncoded());
    }
}

私たちは'salt$iterated_hash(password, salt)'保存してい'salt$iterated_hash(password, salt)' 。 塩は32のランダムなバイトであり、2人の異なる人が同じパスワードを選択した場合、保存されたパスワードはまだ異なって見えるということが目的です。

基本的にhash(hash(hash(... hash(password, salt) ...)))であるiterated_hash 、データベースにアクセスして潜在的な攻撃者がパスワードを推測し、データベース内にハッシュアップします。 ユーザーがログインするたびにiterated_hashを計算する必要がありますが、コンピューティングハッシュの100%近くを費やした攻撃者に比べるとコストはかかりません。

Question

私は、データベースに格納するためにパスワードをハッシュする必要があります。 Javaでこれをどうやって行うことができますか?

プレーンテキストのパスワードを取ってランダムな塩を加え、塩とハッシュされたパスワードをデータベースに保存したいと思っていました。

ユーザーがログインしたいときは、自分のサブミットされたパスワードを取り、アカウント情報からランダムな塩を加え、ハッシュして、アカウント情報で保存されているハッシュパスワードと等しいかどうかを確認することができます。




MessageDigestを使ってハッシュを計算することはできますが、これはセキュリティ面では間違いです。 ハッシュはパスワードを保存するために使用されるのではなく、簡単に解読できます。

パスワードを保存するには、bcrypt、PBKDF2、scryptのような別のアルゴリズムを使用する必要があります。 ここを参照してください




PBKDF2が答えであることをエリクソンに完全に認めます。

このオプションがない場合、またはハッシュを使用する必要がある場合は、Apache Commons DigestUtilsはJCEコードを正しく取得するよりもずっと簡単です: https ://commons.apache.org/proper/commons-codec/apidocs/org/apache /commons/codec/digest/DigestUtils.html

ハッシュを使用する場合は、sha256またはsha512を使用してください。 このページには、パスワード処理とハッシングに関する推奨事項があります(パスワード処理のためのハッシングは推奨しません): http : //www.daemonology.net/blog/2009-06-11-cryptographic-right-answers.html







すべての標準的なハッシュ・スキームの中で、LDAP sshaは最も安全なもので、

http://www.openldap.org/faq/data/cache/347.html

私はそこで指定されたアルゴリズムに従って、MessageDigestを使ってハッシュを行います。

あなたが提案したようにあなたのデータベースに塩を保存する必要があります。