Spring Security 5の新しいパスワードストレージ

Spring Security 5の新しいパスワードストレージ

1. 前書き

最新のSpringSecurityリリースでは、多くの変更が加えられました。 これらの変更の1つは、アプリケーションでパスワードエンコーディングを処理する方法です。

このチュートリアルでは、これらの変更のいくつかについて説明します。

後で、新しい委任メカニズムを構成する方法と、ユーザーに認識されないように既存のパスワードエンコーディングを更新する方法について説明します。

2. Spring Security5.xの関連する変更

Spring Securityチームは、org.springframework.security.authentication.encodingPasswordEncoderを非推奨として宣言しました。 古いインターフェースはランダムに生成されたソルト用に設計されていなかったため、これは論理的な動きでした。 その結果、バージョン5ではこのインターフェイスが削除されました。

さらに、Spring Securityはエンコードされたパスワードの処理方法を変更します。 以前のバージョンでは、各アプリケーションは1つのパスワードエンコーディングアルゴリズムのみを使用していました。

デフォルトでは、StandardPasswordEncoderがそれを処理しました。 エンコードにSHA-256を使用しました。 パスワードエンコーダーを変更することにより、別のアルゴリズムに切り替えることができます。 しかし、アプリケーションは1つのアルゴリズムに厳密に従う必要がありました。

Version 5.0 introduces the concept of password encoding delegation.これで、パスワードごとに異なるエンコーディングを使用できます。 Springは、エンコードされたパスワードにプレフィックスを付ける識別子によってアルゴリズムを認識します。

bcryptでエンコードされたパスワードの例を次に示します。

{bcrypt}$2b$12$FaLabMRystU4MLAasNOKb.HUElBAabuQdX59RWHq5X.9Ghm692NEi

最初にbcryptが中括弧で指定されていることに注意してください。

3. 委任構成

If the password hash has no prefix, the delegation process uses a default encoder.したがって、デフォルトでは、StandardPasswordEncoder.を取得します。

これにより、以前のバージョンのSpring Securityのデフォルト設定と互換性があります。

バージョン5では、Spring SecurityはPasswordEncoderFactories.createDelegatingPasswordEncoder().を導入します。このファクトリメソッドは、DelegationPasswordEncoderの構成済みインスタンスを返します。

プレフィックスのないパスワードの場合、そのインスタンスにより、前述のデフォルトの動作が保証されます。 また、プレフィックスを含むパスワードハッシュの場合、それに応じて委任が行われます。

Spring Securityチームは、サポートされているアルゴリズムを最新バージョンのcorresponding JavaDocにリストします。

もちろん、Springではこの動作を構成できます。

サポートしたいとします。

  • 新しいデフォルトとしてのbcrypt

  • 代替としてscrypt

  • 現在使用されているアルゴリズムとしてのSHA-256。

このセットアップの構成は次のようになります。

@Bean
public PasswordEncoder delegatingPasswordEncoder() {
    PasswordEncoder defaultEncoder = new StandardPasswordEncoder();
    Map encoders = new HashMap<>();
    encoders.put("bcrypt", new BCryptPasswordEncoder());
    encoders.put("scrypt", new SCryptPasswordEncoder());

    DelegatingPasswordEncoder passworEncoder = new DelegatingPasswordEncoder(
      "bcrypt", encoders);
    passworEncoder.setDefaultPasswordEncoderForMatches(defaultEncoder);

    return passworEncoder;
}

4. パスワードエンコーディングアルゴリズムの移行

前のセクションでは、必要に応じてパスワードエンコーディングを構成する方法を検討しました。 Therefore, now we’ll work on how to switch an already encoded password to a new algorithm.

エンコーディングをSHA-256からbcryptに変更したいとしますが、ユーザーがパスワードを変更することは望ましくありません。

考えられる解決策の1つは、ログイン要求を使用することです。 この時点で、プレーンテキストで資格情報にアクセスできます。 それが現在のパスワードを取得して再エンコードできる瞬間です。

したがって、SpringのAuthenticationSuccessEventを使用できます。 このイベントは、ユーザーがアプリケーションに正常にログインした後に発生します。

これがサンプルコードです:

@Bean
public ApplicationListener
  authenticationSuccessListener( PasswordEncoder encoder) {
    return (AuthenticationSuccessEvent event) -> {
        Authentication auth = event.getAuthentication();

        if (auth instanceof UsernamePasswordAuthenticationToken
          && auth.getCredentials() != null) {

            CharSequence clearTextPass = (CharSequence) auth.getCredentials();
            String newPasswordHash = encoder.encode(clearTextPass);

            // [...] Update user's password

            ((UsernamePasswordAuthenticationToken) auth).eraseCredentials();
        }
    };
}

前のスニペットで:

  • 提供された認証の詳細からユーザーテキストをクリアテキストで取得しました

  • 新しいアルゴリズムで新しいパスワードハッシュを作成しました

  • 認証トークンからクリアテキストパスワードを削除しました

デフォルトでは、Spring Securityがパスワードをできるだけ早く削除するため、クリアテキストでパスワードを抽出することはできません。

したがって、パスワードのクリアテキストバージョンを保持するようにSpringを構成する必要があります。

さらに、エンコードの委任を登録する必要があります。

@Configuration
public class PasswordStorageWebSecurityConfigurer
  extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(AuthenticationManagerBuilder auth)
      throws Exception {
        auth.eraseCredentials(false)
          .passwordEncoder(delegatingPasswordEncoder());
    }

    // ...
}

5. 結論

この簡単な記事では、5.xで利用可能な新しいパスワードエンコーディング機能について説明しました。

また、複数のパスワードエンコードアルゴリズムを構成してパスワードをエンコードする方法も確認しました。 さらに、既存のパスワードを壊すことなく、パスワードエンコーディングを変更する方法を検討しました。

最後に、Springイベントを使用して暗号化されたユーザーパスワードを透過的に更新し、ユーザーに開示することなくエンコード戦略をシームレスに変更できるようにする方法を説明しました。

最後に、いつものように、すべてのコード例はGitHub repositoryで利用できます。