1. 概要

このチュートリアルでは、パスワードハッシュの重要性について説明します。

それが何であるか、なぜそれが重要であるか、そしてJavaでそれを行うためのいくつかの安全な方法と安全でない方法を簡単に見ていきます。

2. ハッシュとは何ですか?

Hashing は、暗号化ハッシュ関数と呼ばれる数学関数を使用して、特定のメッセージから文字列またはhashを生成するプロセスです。 。

そこにはいくつかのハッシュ関数がありますが、パスワードのハッシュに合わせたものは、安全にするために4つの主要なプロパティを持っている必要があります。

  1. deterministic である必要があります。同じハッシュ関数によって処理される同じメッセージは、常に同じハッシュを生成する必要があります。
  2. リバーシブルではありません。ハッシュからメッセージを生成することは実用的ではありません。
  3. エントロピーが高くなります。メッセージを少し変更すると、ハッシュが大きく異なります。
  4. そしてそれは衝突に抵抗します:2つの異なるメッセージは同じハッシュを生成するべきではありません

4つのプロパティすべてを備えたハッシュ関数は、パスワードハッシュの有力な候補です。これらを組み合わせると、ハッシュからパスワードをリバースエンジニアリングすることが大幅に困難になるためです。

また、パスワードハッシュ関数は遅い必要があります。 高速アルゴリズムは、ブルートフォース攻撃を支援します。この攻撃では、ハッカーが1秒あたり数十億(または数兆)の潜在的なパスワードをハッシュして比較することでパスワードを推測しようとします。

これらすべての基準を満たすいくつかの優れたハッシュ関数は次のとおりです。 PBKDF2、 BCrypt、 とスクリプト。 しかし、最初に、いくつかの古いアルゴリズムと、それらがもはや推奨されなくなった理由を見てみましょう。

3. 推奨されません:MD5

私たちの最初のハッシュ関数は、1992年に開発されたMD5メッセージダイジェストアルゴリズムです。

JavaのMessageDigestを使用すると、これを簡単に計算でき、他の状況でも役立ちます。

ただし、過去数年にわたって、 MD5は、衝突の生成が計算上容易になったという点で、4番目のパスワードハッシュプロパティに失敗することが発見されました。 さらに、MD5は高速なアルゴリズムであるため、ブルートフォース攻撃に対しては役に立ちません。

これらのため、MD5は推奨されません。

4. 推奨されません:SHA-512

次に、1993年にSHA-0で始まったSecureHashAlgorithmファミリーの一部であるSHA-512を見ていきます。

4.1. なぜSHA-512?

コンピューターの処理能力が向上し、新しい脆弱性が見つかると、研究者は新しいバージョンのSHAを導き出します。 新しいバージョンの長さは次第に長くなります。または、研究者が基礎となるアルゴリズムの新しいバージョンを公開することもあります。

SHA-512は、第3世代のアルゴリズムで最も長いキーを表します。

にはSHAのより安全なバージョンがありますが、SHA-512はJavaに実装されている最強のバージョンです。

4.2. Javaでの実装

それでは、JavaでのSHA-512ハッシュアルゴリズムの実装を見てみましょう。

まず、saltの概念を理解する必要があります。 簡単に言えば、これは新しいハッシュごとに生成されるランダムシーケンスです。

このランダム性を導入することで、ハッシュのエントロピーを増やし、レインボーテーブルと呼ばれる事前にコンパイルされたハッシュのリストからデータベースを保護します。

新しいハッシュ関数は大まかに次のようになります。

salt <- generate-salt;
hash <- salt + ':' + sha512(salt + password)

4.3. 塩の生成

ソルトを導入するには、 java.securitySecureRandomクラスを使用します。

SecureRandom random = new SecureRandom();
byte[] salt = new byte[16];
random.nextBytes(salt);

次に、 MessageDigest クラスを使用して、SHA-512ハッシュ関数をソルトで構成します。

MessageDigest md = MessageDigest.getInstance("SHA-512");
md.update(salt);

これを追加すると、 digest メソッドを使用して、ハッシュ化されたパスワードを生成できるようになります。

byte[] hashedPassword = md.digest(passwordToHash.getBytes(StandardCharsets.UTF_8));

4.4. なぜそれは推奨されないのですか?

ソルトと一緒に使用する場合、 SHA-512は依然として公正なオプションですが、より強力で低速なオプションがあります

また、ここで取り上げる残りのオプションには、構成可能な強度という重要な機能があります。

5. PBKDF2、BCrypt、およびSCrypt

PBKDF2、BCrypt、およびSCryptは、3つの推奨アルゴリズムです。

5.1. なぜそれらが推奨されるのですか?

これらのそれぞれは遅く、それぞれが構成可能な強さを持っているという素晴らしい機能を持っています。

これは、コンピューターの強度が増すにつれて、入力を変更することでアルゴリズムの速度を落とすことができることを意味します。

5.2. JavaでのPBKDF2の実装

現在、ソルトはパスワードハッシュの基本原則であるため、PBKDF2にも1つ必要です。

SecureRandom random = new SecureRandom();
byte[] salt = new byte[16];
random.nextBytes(salt);

次に、PBEKeySpecSecretKeyFactoryを作成し、PBKDF2WithHmacSHA1アルゴリズムを使用してインスタンス化します。

KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 65536, 128);
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");

3番目のパラメーター( 65536 )は、事実上強度パラメーターです。 これは、このアルゴリズムが実行される反復回数を示し、ハッシュの生成にかかる時間を増やします。

最後に、SecretKeyFactoryを使用してハッシュを生成できます。

byte[] hash = factory.generateSecret(spec).getEncoded();

5.3. JavaでのBCryptとSCryptの実装

したがって、 BCryptおよびSCryptのサポートは、Java にはまだ付属していませんが、一部のJavaライブラリはそれらをサポートしています。

それらのライブラリの1つはSpringSecurityです。

6. SpringSecurityによるパスワードハッシュ

JavaはPBKDF2とSHAの両方のハッシュアルゴリズムをネイティブにサポートしていますが、BCryptとSCryptのアルゴリズムはサポートしていません。

幸いなことに、Spring Securityには、PasswordEncoderインターフェイスを介してこれらすべての推奨アルゴリズムがサポートされています。

  • Pbkdf2PasswordEncoderはPBKDF2を提供します
  • BCryptPasswordEncoder は私たちにBCryptを提供し、
  • SCryptPasswordEncoderはSCryptを提供します

PBKDF2、BCrypt、およびSCryptのパスワードエンコーダーはすべて、パスワードハッシュの必要な強度を構成するためのサポートが付属しています。

Spring Securityベースのアプリケーションがなくても、これらのエンコーダーを直接使用できます。 または、Spring Securityでサイトを保護している場合は、DSLまたは依存性注入を介して目的のパスワードエンコーダーを構成できます。

また、上記の例とは異なり、これらの暗号化アルゴリズムは内部的にソルトを生成します。 アルゴリズムは、後でパスワードの検証に使用するために、出力ハッシュ内にソルトを格納します。

7. 結論

そこで、パスワードハッシュについて深く掘り下げました。 概念とその使用法を探る。

また、Javaでコーディングする前に、いくつかの履歴ハッシュ関数と現在実装されているハッシュ関数を確認しました。

最後に、Spring Securityにはパスワード暗号化クラスが付属しており、さまざまなハッシュ関数の配列が実装されていることがわかりました。

いつものように、コードはGitHubで入手できます。