1概要

この記事では、ユーザーがログインした後に、最初に要求されたURLにユーザーをリダイレクトする方法に焦点を当てます。

これまで、さまざまな種類のユーザーに対して

Spring Security__でログインした後にさまざまなページにリダイレクトする方法

を見てきました。

この記事はリンクのトップに基づいています:/spring-security-login[Spring Securityログイン]チュートリアル。


2一般的な方法

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

  • HTTP Refererヘッダを使う

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

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


  • HTTP Referer

    ヘッダーの使用** はほとんどのブラウザや

    HTTP

    クライアントにとって自動的に

    Referer

    を設定するので、簡単な方法です。ただし、

    Referer

    は偽造可能でクライアントの実装に依存しているため、リダイレクトの実装に

    HTTP Referer

    ヘッダーを使用することは一般的に推奨されていません。

  • セッション内の元のリクエストを保存する** ことは、この種のリダイレクトを実装するための安全で堅牢な方法です。元のURLの他に、元のリクエスト属性とカスタムプロパティをセッションに保存できます。

  • そしてリダイレクトされたログインURLにオリジナルのURLを追加すること** は通常SSO実装で見られます。 SSOサービスを介して認証されると、ユーザーは最初に要求されたページにURLが追加された状態でリダイレクトされます。追加されたURLが正しくエンコードされていることを確認する必要があります。

別の同様の実装は、ログインフォーム内の隠しフィールドに元のリクエストURLを入れることです。しかし、これは

HTTP Referer

を使用することに勝るものではありません。

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


3

AuthenticationSuccessHandler


フォームベース認証では、リダイレクトはログイン直後に行われ、https://github.com/spring-projects/spring-security/blob/master/web/src/main/java/org/springframework/securityで処理されます

Spring Security

の/web/authentication/AuthenticationSuccessHandler.java[

AuthenticationSuccessHandler

]インスタンス。

3つのデフォルト実装が提供されています。



SimpleUrlAuthenticationSuccessHandler


ghttps//.com/spring-projects/spring-security/blob/master/web/src/main/java/org/springframework/security/web/authentication/SavedRequestAwareAuthenticationSuccessHandler.java[

SavedRequestAwareAuthenticationSuccessHandler

]およびhttps://github.com/spring- projects/spring-security/blob/master/web/src/main/java/org/springframework/security/web/authentication/ForwardAuthenticationSuccessHandler.java[

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は次のようになります。

<http>
    <intercept-url pattern="/login" access="permitAll"/>
    <intercept-url pattern="/** ** " access="isAuthenticated()"/>
    <form-login/>
</http>

セキュリティ保護されたリソースが “/secure”の場所にあるとします。初めてリソースにアクセスすると、ログインページにリダイレクトされます。資格情報を入力してログインフォームを送信すると、最初にリクエストされたリソースの場所にリダイレクトされます。

@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)

によって、Refererベースのリダイレクトを有効にすることができます。

public class RefererRedirectionAuthenticationSuccessHandler
  extends SimpleUrlAuthenticationSuccessHandler
  implements AuthenticationSuccessHandler {

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

}

それを

RedirectionSecurityConfig



AuthenticationSuccessHandler

として使用します。

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

そしてXML設定の場合:

<http>
    <intercept-url pattern="/login" access="permitAll"/>
    <intercept-url pattern="/** ** " access="isAuthenticated()"/>
    <form-login authentication-success-handler-ref="refererHandler"/>
</http>

<beans:bean
  class="RefererRedirectionAuthenticationSuccessHandler"
  name="refererHandler"/>


3.3. フードの下


Spring Security

のこれらの使いやすい機能に魔法はありません。

保護されたリソースが要求されているとき、その要求はさまざまなフィルタのチェーンによってフィルタ処理されます。認証主体と権限がチェックされます。リクエストセッションがまだ認証されていない場合は、https://github.com/spring-projects/spring-security/blob/master/core/src/main/java/org/springframework/security/core/認証認証例外。]がスローされます。


AuthenticationException

は__httpsでキャッチされます。認証プロセスが開始され、その結果ログインページにリダイレクトされます。

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

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

  • 検証や追加のメソッド制御が適用されていない場合、ここで説明したすべての実装は特定の攻撃に対して脆弱です。

このような攻撃により、ユーザーが悪質なサイトにリダイレクトされる可能性があります。


OWASP

は、未検証のリダイレクトや転送を処理するためにhttps://www.owasp.org/index.php/Unvalidated

Redirects

and

Forwards

Cheat__Sheet[簡易シート]を提供しています。私たちが自分自身で実装を構築する必要があるならば、これは大いに役立つでしょう。

この記事の完全な実装コードはhttps://github.com/eugenp/tutorials/tree/master/spring-security-mvc-login[over Github]です。