Spring + Thymeleaf ± Ajax通信時の403 forbidden

今回は、Spring+Thymeleaf+Ajax通信時に発生した403エラーについてメモしていこうと思います。

403エラーとは?

クロスサイトリクエストフォージェリは、ウェブアプリケーションの脆弱性を悪用するサイバー攻撃の一種です。文字通り「サイト横断的に(Cross Site)リクエストを偽装(Request Forgeries)する」攻撃です。CSRFと略されシーサーフと呼ばれることが多くなっています。

具体的に説明します。攻撃者は罠となるサイトを用意し、ユーザーが罠にかかるのを待つかリンクやメールなどで利用者を罠サイトへ誘導します。誘い込まれたユーザーが罠サイトにアクセスし、その際にユーザーがターゲットとなるウェブサイトへログイン状態になっていると、そのウェブサイトに偽のリクエストが送信・実行されてしまうという攻撃です。

上記の内容を無視してリクエストを投げると403エラーが発生します。なので、CRSFを通して認証し、リクエストを投げる必要があります。

エラーが発生しないようにするには?

状況や方式によって使い方はいくつかあります。

  • Formタグを利用する。
  • Ajaxのヘッダーに追加してリクエストをねげる。
  • Spring Securityのcsrfのオプションを無効にする。

今回は個人のプロジェクトなので、csrfのオプションを向こうにしました。

@Configuration
public class SpringBootSecurityConfiguration extends WebSecurityConfigurerAdapter {
    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("user").password("{noop}password").roles("USER");
    }

    @Override public void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .antMatchers("/**").hasAnyRole("USER")
                .and()
                .formLogin().loginPage("/login").permitAll();
        http.csrf().disable(); // ①無効にする
    }
}
  • ①のようにcsrf().disable()を使って無効にできます。

Ajax通信時、csrfメタ情報をセットする方法

これはAjaxでリクエストを送る前にヘッダー情報にcsrf情報をセットしてリクエストを投げる方法です。

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org"
        xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>
<script type="text/javascript" src="js/jquery-3.4.1.min.js"></script>
<script type="text/javascript">
        $(function() {
         let token = $("meta[name='_csrf']").attr("content"); //①
         let header = $("meta[name='_csrf_header']").attr("content"); //②
         $(document).ajaxSend(function(e, xhr, options) { /③
          xhr.setRequestHeader(header, token);
         });

         $.ajax({
          type : "post",
          //type : "get",
          url : "api/hoge",
          contentType : "application/json"
         })
         .done( (result) => {
          alert(result.msg);
         })
        });
</script>
</head>
<body>
<input type="button" id="hoge" value="ボタン" />
</body>
// ④
<meta th:name="_csrf" th:content="${_csrf.token}"/>
<meta th:name="_csrf_header" th:content="${_csrf.headerName}"/>
</html>
  • ①、②:メタ情報からcsrf関連情報を取得します。
  • ③:上記で取得した内容をリクエスト情報にセットします。
  • ④:ログイン時のcsrf認証情報が入っています。

終わりに

間違っているところもあるかと思いますが、それはやりながら身に付けるしかないと思います。

Formの方法は気になりますが、調べてはいないので今度にしておきたいと思います。

「Spring + Thymeleaf ± Ajax通信時の403 forbidden」への1件のフィードバック

  1. Лично я так увлекаюсь чтивом Всех ваших текстов, что вообще как скоро завершаю, везде уже уже давным давно за полночь

    いいね

コメントを残す