Spring SecurityでCSRF対策を有効にしてログアウトを実装する時の注意点


概要

本記事では、Spring SecurityでCSRF対策を有効にしてログアウトを実装した時に陥りがちなエラーとその対策について紹介します。

動作確認環境

  • OS: macOS Mojave 10.14.2
  • Spring Boot version: 2.1.2.RELEASE

Spring SecurityでCSRF対策を行なってログアウトを実装した時に陥りがちなエラー

Spring SecurityでCSRF対策を有効にしている状態では、データをPOSTで送信する時にCSRFのトークン値を送らなければなりません。Thymeleafを使用すると、formタグでth:actionを使用するだけで、CSRFのトークン値を自動作成し、送信します。
 したがって、Spring SecurityとThymeleafを使用した場合、CSRF対策には基本的にはformタグでth:actionを書くだけでいいのですが、リンクを使ってログアウトを実装する際には注意が必要です。
何も考えずにログアウトをGETで行うと404エラーが発生してしまいます。
 Spring Securityでは、基本的にはGETで送信する時にはCSRFのトークンチェックを行いませんが、ログアウトの場合にはGETで送信した時にもCSRFのトークンチェックを行います。しかし、GETで送信した場合にはトークン値は自動作成されません。
 したがって、ログアウトをGETで行なった場合、404エラーが発生してしまいます。以下に例を示します。

 以下のコードでログアウトを実装します。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>メインページ</title>
</head>
<body>
メインページです。
<a href="/logout">ログアウト</a>
</body>
</html>

 Spring Securityでは、ログアウトのリンク先に"/logout"を指定するだけでログアウトできるのですが、この状態でログアウトのリンクをクリックすると、404エラーが発生してしまいます。

CSRF対策を行なった時のログアウト実装

ログアウトをGETで行なった場合、CSRFトークン値が自動作成されず、エラーになってしまうため、javascriptを使って以下のようにログアウト時のメソッドをPOSTに変更します。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>メインページ</title>
</head>
<body>
メインページです。
<form th:action="@{/logout}" name="logout" method="POST">
    <a href="javascript:logout.submit()">ログアウト</a>
</form>
</body>
</html>

すると、CSRF対策を有効にした状態でリンクからログアウトできるようになります。