Spring Security - ログイン後に前のURLにリダイレクトする

Spring Security –ログイン後に以前のURLにリダイレクトする

1. 概要

この記事では、how to redirect a user back to the originally requested URL – after they log inに焦点を当てます。

以前は、さまざまなタイプのユーザーのhow to redirect to different pages after login with Spring Securityを確認し、さまざまなタイプのredirections with Spring MVCについて説明しました。

この記事は、Spring Security Loginチュートリアルのトップに基づいています。

2. 一般的な方法

ログイン後にリダイレクトロジックを実装する最も一般的な方法は次のとおりです。

  • HTTP Refererヘッダーを使用

  • セッションで元のリクエストを保存する

  • リダイレクトされたログインURLに元のURLを追加する

Using the HTTP Referer headerは簡単な方法で、ほとんどのブラウザとHTTPクライアントはRefererを自動的に設定します。 ただし、Refererは偽造可能であり、クライアントの実装に依存しているため、HTTP Refererヘッダーを使用してリダイレクトを実装することは一般的に推奨されていません。

Saving the original request in the sessionは、この種のリダイレクトを実装するための安全で堅牢な方法です。 元のURLに加えて、元の要求属性とカスタムプロパティをセッションに保存できます。

And appending original URL to the redirected login URLは通常、SSOの実装で見られます。 SSOサービスを介して認証されると、ユーザーは最初にリクエストされたページにリダイレクトされ、URLが追加されます。 追加したURLが適切にエンコードされていることを確認する必要があります。

別の同様の実装では、ログインフォーム内の非表示フィールドに元のリクエストURLを配置します。 しかし、これはHTTP Refererを使用するよりも優れています

Spring Securityでは、最初の2つのアプローチがネイティブにサポートされています。

3. AuthenticationSuccessHandler

フォームベース認証では、リダイレクトはログインの直後に発生します。これは、Spring SecurityAuthenticationSuccessHandlerインスタンスで処理されます。

3つのデフォルトの実装が提供されています:SimpleUrlAuthenticationSuccessHandlerSavedRequestAwareAuthenticationSuccessHandler、およびForwardAuthenticationSuccessHandler。 最初の2つの実装に焦点を当てます。

3.1. SavedRequestAwareAuthenticationSuccessHandler

SavedRequestAwareAuthenticationSuccessHandlerは、セッションに保存された保存済みリクエストを利用します。 ログインに成功すると、ユーザーは元のリクエストで保存されたURLにリダイレクトされます。

フォームログインの場合、SavedRequestAwareAuthenticationSuccessHandlerがデフォルトのAuthenticationSuccessHandlerとして使用されます。

@Configuration
@EnableWebSecurity
public class RedirectionSecurityConfig extends WebSecurityConfigurerAdapter {

    //...

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
          .authorizeRequests()
          .antMatchers("/login*")
          .permitAll()
          .anyRequest()
          .authenticated()
          .and()
          .formLogin();
    }

}

そして、同等のXMLは次のようになります。


    
    
    

場所「/ secured」にセキュリティで保護されたリソースがあるとします。 リソースに初めてアクセスすると、ログインページにリダイレクトされます。認証情報を入力してログインフォームを投稿すると、最初にリクエストされたリソースの場所にリダイレクトされます。

@Test
public void givenAccessSecuredResource_whenAuthenticated_thenRedirectedBack()
  throws Exception {

    MockHttpServletRequestBuilder securedResourceAccess = get("/secured");
    MvcResult unauthenticatedResult = mvc
      .perform(securedResourceAccess)
      .andExpect(status().is3xxRedirection())
      .andReturn();

    MockHttpSession session = (MockHttpSession) unauthenticatedResult
      .getRequest()
      .getSession();
    String loginUrl = unauthenticatedResult
      .getResponse()
      .getRedirectedUrl();
    mvc
      .perform(post(loginUrl)
        .param("username", userDetails.getUsername())
        .param("password", userDetails.getPassword())
        .session(session)
        .with(csrf()))
      .andExpect(status().is3xxRedirection())
      .andExpect(redirectedUrlPattern("**/secured"))
      .andReturn();

    mvc
      .perform(securedResourceAccess.session(session))
      .andExpect(status().isOk());
}

3.2. SimpleUrlAuthenticationSuccessHandler

SavedRequestAwareAuthenticationSuccessHandlerと比較して、SimpleUrlAuthenticationSuccessHandlerは、リダイレクトの決定に関してより多くのオプションを提供します。

setUserReferer(true)によってリファラーベースのリダイレクトを有効にできます。

public class RefererRedirectionAuthenticationSuccessHandler
  extends SimpleUrlAuthenticationSuccessHandler
  implements AuthenticationSuccessHandler {

    public RefererRedirectionAuthenticationSuccessHandler() {
        super();
        setUseReferer(true);
    }

}

次に、それをRedirectionSecurityConfigAuthenticationSuccessHandlerとして使用します。

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
      .authorizeRequests()
      .antMatchers("/login*")
      .permitAll()
      .anyRequest()
      .authenticated()
      .and()
      .formLogin()
      .successHandler(new RefererAuthenticationSuccessHandler());
}

また、XML構成の場合:


    
    
    


3.3. フードの下

Spring Securityのこれらの使いやすい機能には魔法はありません。 保護されたリソースが要求されると、要求はさまざまなフィルターのチェーンによってフィルターされます。 認証プリンシパルと許可が確認されます。 リクエストセッションがまだ認証されていない場合、AuthenticationExceptionがスローされます。

AuthenticationExceptionは、認証プロセスが開始されるExceptionTranslationFilter,に捕捉され、ログインページにリダイレクトされます。

public class ExceptionTranslationFilter extends GenericFilterBean {

    //...

    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
      throws IOException, ServletException {
        //...

        handleSpringSecurityException(request, response, chain, ase);

        //...
    }

    private void handleSpringSecurityException(HttpServletRequest request,
      HttpServletResponse response, FilterChain chain, RuntimeException exception)
      throws IOException, ServletException {

        if (exception instanceof AuthenticationException) {

            sendStartAuthentication(request, response, chain,
              (AuthenticationException) exception);

        }

        //...
    }

    protected void sendStartAuthentication(HttpServletRequest request,
      HttpServletResponse response, FilterChain chain,
      AuthenticationException reason) throws ServletException, IOException {

       SecurityContextHolder.getContext().setAuthentication(null);
       requestCache.saveRequest(request, response);
       authenticationEntryPoint.commence(request, response, reason);
    }

    //...

}

ログイン後、上記のように、AuthenticationSuccessHandlerで動作をカスタマイズできます。

4. 結論

このSpring Securityの例では、ログイン後のリダイレクトの一般的な方法について説明し、SpringSecurityを使用した実装について説明しました。

all the implementations we mentioned are vulnerable to certain attacks if no validation or extra method controls are appliedに注意してください。 このような攻撃により、ユーザーが悪意のあるサイトにリダイレクトされる可能性があります。

OWASPは、検証されていないリダイレクトと転送を処理するのに役立つcheat sheetを提供しています。 独自に実装を構築する必要がある場合、これは多くの助けになります。

この記事の完全な実装コードはover on Githubにあります。