Spring MVCとThymeleafによるCSRF保護

Spring MVCとThymeleafによるCSRF保護

1. 前書き

Thymeleafは、HTML、XML、JavaScript、CSS、およびプレーンテキストを処理および作成するためのJavaテンプレートエンジンです。 ThymeleafとSpringの紹介については、this writeupをご覧ください。

この記事では、Thymeleafアプリケーションを使用してSpring MVCでprevent Cross-Site Request Forgery (CSRF) attacksを実行する方法について説明します。 具体的には、HTTP POSTメソッドのCSRF攻撃をテストします。

CSRFは、現在認証されているWebアプリケーションでエンドユーザーに不要なアクションを実行させる攻撃です。

2. Mavenの依存関係

最初に、ThymeleafとSpringを統合するために必要な構成を見てみましょう。 依存関係にはthymeleaf-springライブラリが必要です。


    org.thymeleaf
    thymeleaf
    3.0.9.RELEASE


    org.thymeleaf
    thymeleaf-spring4
    3.0.9.RELEASE

Spring 4プロジェクトの場合、thymeleaf-spring5の代わりにthymeleaf-spring4ライブラリを使用する必要があることに注意してください。 依存関係の最新バージョンはhereで見つかる可能性があります。

さらに、Spring Securityを使用するには、次の依存関係を追加する必要があります。


    org.springframework.security
    spring-security-web
    5.0.6.RELEASE


    org.springframework.security
    spring-security-config
    5.0.6.RELEASE

2つのSpringSecurity関連ライブラリの最新バージョンはherehereで利用できます。

3. Java設定

hereをカバーするThymeleaf構成に加えて、SpringSecurityの構成を追加する必要があります。 そのためには、クラスを作成する必要があります。

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
public class WebMVCSecurity extends WebSecurityConfigurerAdapter {

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
          .withUser("user1").password("{noop}user1Pass")
          .authorities("ROLE_USER");
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/resources/**");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
          .authorizeRequests()
          .anyRequest()
          .authenticated()
          .and()
          .httpBasic();
    }
}

セキュリティ構成の詳細と説明については、Security with Springシリーズを参照してください。

CSRF protection is enabled by default with Java configuration.この便利な機能を無効にするには、これをconfigure(…)メソッドに追加する必要があります。

.csrf().disable()

XML構成では、CSRF保護を手動で指定する必要があります。そうしないと、動作しません。


    

    

また、ログインフォームでログインページを使用している場合は、CSRFトークンを常に手動でコードの非表示パラメーターとしてログインフォームに含める必要があることに注意してください。

残りのフォームについては、CSRFトークンが非表示入力のフォームに自動的に追加されます。


4. ビューの構成

フォームアクションとテスト手順の作成を含むHTMLファイルの主要部分に進みましょう。 最初のビューでは、新しい学生をリストに追加しようとします:




Add Student


    

Add Student

このビューでは、idnamegender、およびpercentageを提供することにより、リストに学生を追加しています(オプションで、フォームの検証に記載されています)。 このフォームを実行する前に、Webアプリケーションで認証するためにuserpasswordを指定する必要があります。

4.1. ブラウザのCSRF攻撃テスト

次に、2番目のHTMLビューに進みます。 その目的は、CSRF攻撃を試みることです。




    


アクションURLはhttp://localhost:8080/spring-thymeleaf/saveStudentであることがわかっています。 ハッカーはこのページにアクセスして攻撃を行いたいと考えています。

テストするには、アプリケーションにログインせずにHTMLファイルを別のブラウザーで開きます。 フォームを送信しようとすると、次のページが届きます。

image

 

CSRFトークンなしでリクエストを送信したため、リクエストは拒否されました。

CSRFトークンを保存するためにHTTPセッションが使用されることに注意してください。 要求が送信されると、Springはユーザーがハッキングされていないことを確認するために、生成されたトークンをセッションに保存されているトークンと比較します。

4.2. JUnitCSRF攻撃テスト

ブラウザを使用してCSRF攻撃をテストしたくない場合は、クイック統合テストを使用してテストすることもできます。そのテストのSpring構成から始めましょう。

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(classes = {
  WebApp.class, WebMVCConfig.class, WebMVCSecurity.class, InitSecurity.class })
public class CsrfEnabledIntegrationTest {

    // configuration

}

そして、実際のテストに進みます。

@Test
public void addStudentWithoutCSRF() throws Exception {
    mockMvc.perform(post("/saveStudent").contentType(MediaType.APPLICATION_JSON)
      .param("id", "1234567").param("name", "Joe").param("gender", "M")
      .with(testUser())).andExpect(status().isForbidden());
}

@Test
public void addStudentWithCSRF() throws Exception {
    mockMvc.perform(post("/saveStudent").contentType(MediaType.APPLICATION_JSON)
      .param("id", "1234567").param("name", "Joe").param("gender", "M")
      .with(testUser()).with(csrf())).andExpect(status().isOk());
}

最初のテストでは、CSRFトークンが欠落しているため、禁止ステータスになりますが、2番目のテストは適切に実行されます。

5. 結論

この記事では、Spring SecurityとThymeleafフレームワークを使用してCSRF攻撃を防ぐ方法について説明しました。

このチュートリアルの完全な実装はthe GitHub projectにあります。これはEclipseベースのプロジェクトであるため、そのままインポートして実行するのは簡単です。