今回は、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の方法は気になりますが、調べてはいないので今度にしておきたいと思います。

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