1. 概要

Spring Security 4では、メモリ内認証を使用してパスワードをプレーンテキストで保存することが可能でした。

バージョン5でのパスワード管理プロセスの大幅な見直しにより、パスワードをエンコードおよびデコードするためのより安全なデフォルトメカニズムが導入されました。 つまり、Springアプリケーションがパスワードをプレーンテキストで保存している場合、SpringSecurity5にアップグレードすると問題が発生する可能性があります。

この短いチュートリアルでは、これらの潜在的な問題の1つについて説明し、解決策を示します。

2. 春のセキュリティ4

まず、単純なメモリ内認証を提供する標準のセキュリティ構成を示します(Spring 4で有効)。

@Configuration
public class InMemoryAuthWebSecurityConfigurer 
  extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(AuthenticationManagerBuilder auth) 
      throws Exception {
        auth.inMemoryAuthentication()
          .withUser("spring")
          .password("secret")
          .roles("USER");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
          .antMatchers("/private/**")
          .authenticated()
          .antMatchers("/public/**")
          .permitAll()
          .and()
          .httpBasic();
    }
}

この構成は、すべての / private / マップされたメソッドの認証と、 /public/。の下のすべてのパブリックアクセスを定義します。

Spring Security 5で同じ構成を使用すると、次のエラーが発生します。

java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id "null"

このエラーは、メモリ内認証にパスワードエンコーダーが構成されていないため、指定されたパスワードをデコードできなかったことを示しています。

3. 春のセキュリティ5

Delegating PasswordEncoderPasswordEncoderFactoriesクラスで定義することにより、このエラーを修正できます。

このエンコーダーを使用して、 AuthenticationManagerBuilder:でユーザーを構成します

@Configuration
public class InMemoryAuthWebSecurityConfigurer 
  extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(AuthenticationManagerBuilder auth) 
      throws Exception {
        PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
        auth.inMemoryAuthentication()
          .withUser("spring")
          .password(encoder.encode("secret"))
          .roles("USER");
    }
}

現在、この構成では、BCryptを使用してメモリ内のパスワードを次の形式で保存しています。

{bcrypt}$2a$10$MF7hYnWLeLT66gNccBgxaONZHbrSMjlUofkp50sSpBw2PJjUqU.zS

独自のパスワードエンコーダーのセットを定義することもできますが、PasswordEncoderFactoriesで提供されているデフォルトのエンコーダーを使用することをお勧めします。

3.2. NoOpPasswordEncoder

何らかの理由で、構成されたパスワードをエンコードしたくない場合は、NoOpPasswordEncoderを使用できます。

そのためには、 password()メソッドに提供するパスフレーズの前に{noop}識別子を付けるだけです。

@Configuration
public class InMemoryNoOpAuthWebSecurityConfigurer 
  extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(AuthenticationManagerBuilder auth) 
      throws Exception {
        auth.inMemoryAuthentication()
          .withUser("spring")
          .password("{noop}secret")
          .roles("USER");
    }
}

このように、Spring Securityは、ユーザーから提供されたパスワードを上記で構成したパスワードと比較するときに、内部でNoOpPasswordEncoderを使用します。

ただし、本番アプリケーションではこのアプローチを使用しないでください!公式ドキュメントに記載されているように、NoOpPasswordEncoderは非推奨になりましたこれはレガシー実装であることを示しています。そしてそれを使用することは安全でないと見なされます。

3.3. 既存のパスワードの移行

次の方法で、既存のパスワードを推奨されるSpringSecurity5標準に更新できます。

  • プレーンテキストで保存されたパスワードを、エンコードされた値で更新します。
String encoded = new BCryptPasswordEncoder().encode(plainTextPassword);
  • ハッシュ化された保存済みパスワードの前に、既知のエンコーダー識別子を付けます。
{bcrypt}$2a$10$MF7hYnWLeLT66gNccBgxaONZHbrSMjlUofkp50sSpBw2PJjUqU.zS
{sha256}97cde38028ad898ebc02e690819fa220e88c62e0699403e94fff291cfffaf8410849f27605abcbc0
  • 保存されたパスワードのエンコードメカニズムが不明な場合に、ユーザーにパスワードの更新を要求する

4. 結論

この簡単な例では、新しいパスワードストレージメカニズムを使用して、有効なSpring4メモリ内認証構成をSpring5に更新しました。

いつものように、ソースコードはGitHubプロジェクトにあります。