SpringSecurity5の新しいパスワードストレージ
1. 序章
最新のSpringSecurityリリースでは、多くの変更が加えられました。 これらの変更の1つは、アプリケーションでパスワードエンコーディングを処理する方法です。
このチュートリアルでは、これらの変更のいくつかを調べます。
後で、ユーザーが認識しないように、新しい委任メカニズムを構成する方法と、既存のパスワードエンコーディングを更新する方法を説明します。
2. SpringSecurity5.xの関連する変更
Spring Securityチームは、org.springframework.security.authentication.encodingのPasswordEncoderを非推奨として宣言しました。 古いインターフェースはランダムに生成されたソルト用に設計されていなかったため、これは論理的な動きでした。 その結果、バージョン5ではこのインターフェイスが削除されました。
さらに、Spring Securityは、エンコードされたパスワードの処理方法を変更します。 以前のバージョンでは、各アプリケーションは1つのパスワードエンコーディングアルゴリズムのみを採用していました。
デフォルトでは、StandardPasswordEncoderはそれを処理します。 エンコーディングにはSHA-256を使用しました。 パスワードエンコーダーを変更することで、別のアルゴリズムに切り替えることができます。 しかし、私たちのアプリケーションは、正確に1つのアルゴリズムに固執する必要がありました。
バージョン5.0では、パスワードエンコーディングの委任の概念が導入されています。これで、パスワードごとに異なるエンコーディングを使用できるようになりました。 Springは、エンコードされたパスワードの前に付けられた識別子によってアルゴリズムを認識します。
bcryptでエンコードされたパスワードの例を次に示します。
{bcrypt}$2b$12$FaLabMRystU4MLAasNOKb.HUElBAabuQdX59RWHq5X.9Ghm692NEi
bcryptが最初に中括弧で指定されていることに注意してください。
3. 委任構成
パスワードハッシュにプレフィックスがない場合、委任プロセスはデフォルトのエンコーダーを使用します。したがって、デフォルトでは、StandardPasswordEncoder。を取得します。
これにより、以前のSpringSecurityバージョンのデフォルト構成と互換性があります。
バージョン5では、SpringSecurityはPasswordEncoderFactories.createDelegatingPasswordEncoder()。を導入します。このファクトリメソッドは、DelegationPasswordEncoderの構成済みインスタンスを返します。
プレフィックスのないパスワードの場合、そのインスタンスは上記のデフォルトの動作を保証します。 また、プレフィックスを含むパスワードハッシュの場合、委任はそれに応じて行われます。
Spring Securityチームは、サポートされているアルゴリズムを対応するJavaDocの最新バージョンにリストしています。
もちろん、Springではこの動作を構成できます。
サポートしたいとします。
- 新しいデフォルトとしてのbcrypt
- 代替としてscrypt
- 現在使用されているアルゴリズムとしてのSHA-256。
このセットアップの構成は次のようになります。
@Bean
public PasswordEncoder delegatingPasswordEncoder() {
PasswordEncoder defaultEncoder = new StandardPasswordEncoder();
Map<String, PasswordEncoder> 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. パスワードエンコーディングアルゴリズムの移行
前のセクションでは、必要に応じてパスワードエンコーディングを構成する方法について説明しました。 したがって、ここでは、すでにエンコードされているパスワードを新しいアルゴリズムに切り替える方法に取り組みます。
エンコーディングをSHA-256からbcryptに変更したいとしますが、ユーザーがパスワードを変更することは望ましくありません。
考えられる解決策の1つは、ログイン要求を使用することです。 この時点で、プレーンテキストの資格情報にアクセスできます。 これが、現在のパスワードを取得して再エンコードできる瞬間です。
したがって、そのためにSpringのAuthenticationSuccessEventを使用できます。 このイベントは、ユーザーがアプリケーションに正常にログインした後に発生します。
サンプルコードは次のとおりです。
@Bean
public ApplicationListener<AuthenticationSuccessEvent>
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セキュリティがパスワードをできるだけ早く削除するため、クリアテキストでパスワードを抽出することはできません。
したがって、パスワードのクリアテキストバージョンを保持するように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リポジトリで入手できます。