IIn the spring boot application, if the security module is configured with CSRF – Cross-Site Request Forgery, all requests are verified for a CSRF attack. In this case, the logout link does not work. If the CSRF is disabled in the security configuration, the logout link will work without any problems. It allows the user to log out and return to the home page or login page.

In this post, we’ll see why this logout link doesn’t work and how to fix the logout problem and allow the user to log out from the spring boot security application.

Whitelabel Error Page

This application has no explicit mapping for /error, so you are seeing this as a fallback.

Tue Feb 04 20:22:41 IST 2020
There was an unexpected error (type=Forbidden, status=403).
Forbidden
Whitelabel Error Page

This application has no explicit mapping for /error, so you are seeing this as a fallback.

Tue Feb 04 20:22:41 IST 2020
There was an unexpected error (type=Forbidden, status=403).
Invalid CSRF Token 'null' was found on the request parameter '_csrf' or header 'X-CSRF-TOKEN'.


Root Cause

The spring boot application is configured to run with CSRF token. All the data updating request calls must be HTTP Post calls. The login page is changed to submit using post method with the CSRF token. But the logout call uses the default logout url in the the spring boot security framework

By default, the security framework logout call is the get method and does not provide a valid CSRF token. Therefore the logout call does not working in spring boot security module with CSRF enabled.



How to reproduce this issue

In the spring boot application, add the spring boot security module to the pom.xml file. Using jsp files to build login and logout features. In the security configuration, the CSRF feature should be enabled. This issue will occur if you click on the logout button. The example below illustrates how this problem can be replicated.

pom.xml

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-security</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-taglibs</artifactId>
		</dependency>

application.properties

spring.mvc.view.prefix=/WEB-INF/jsp/
spring.mvc.view.suffix=.jsp

TestController.java

package com.yawintutor;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

@Controller
@RequestMapping
public class TestController {

	@RequestMapping("/")
	public ModelAndView defaultHome() {
		System.out.println("/ called");
		return new ModelAndView("home");
	}

	@RequestMapping("/login")
	public ModelAndView login() {
		System.out.println("/login called");
		return new ModelAndView("login");
	}
}

login.jsp

<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
<center>
<h1>Welcome to Spring Boot Security</h1>

<h2>Login Page</h2>

<form method="POST" action="/login">
	User Name : <input type="text" name="username" value="user"/><br><br>
	Password  : <input type="password" name="password" value="password"/><br><br>
	<sec:csrfInput />  
	<input type="submit" name="submit"/>
</form>
</center>

home.jsp

<center>
<h1>Welcome to Spring Boot Simple Security Example</h1>
<a href="/logout">logout</a>
</center>



Solution 1

The logout link is called as a HTTP Get call. Change the HTTP Get to a HTTP Post call. The following example shows the sample code for the HTTP Post request. This is going to address this issue.

home.jsp

<center>
<h1>Welcome to Spring Boot Simple Security Example</h1>
<form action="/logout" method=post>
    <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
    <input type="submit" value="logout">
</form>
</center>


Solution 2

If you still have issue in spring boot security, please follow the below steps to fix the issue



Leave a Reply