The CSRF Protection with Spring Security

In this article I will explain the CSRF attack, the Cross-Site Request Forgery attack. I will show how Spring Security can protect against this attack, in both a server side rendering server and with a separated frontend and the Cookie repository.

Content

  • The CSRF Attack
  • The CSRF Protection with Spring Security
    • Allowed Origins
    • CSRF Token Repository
    • The CSRF Endpoint

For more details, watch this video.

The code of the current article is available in this repository.

The CSRF Attack

First of all, what is a CSRF attack? As specified in the OWASP definition: the Cross Site Request Forgery is an attack that forces an end user to execute unwanted actions on a web application in which they are currently authenticated.

Let’s say I’m a frequent user of a social network website. When the engineers developed the social network, they faced to a problem. A quick search in the web showed them that allowing all the origins to perform actions on their backend is a solution. But maybe this isn’t the correct solution.

config.addAllowedOrigin("*");

They quickly realized that more requests failed. All the requests which implied some modifications: POST, PUT, DELETE or PATCH. Another quick search showed them another solution.

http.csrf().disable();

Yes, Spring Security has already enabled by default CSRF. From there, all the website seemed to work perfectly.

What was the first mistake made? Allowing all the origins to perform requests on the backend. This means that, someday, I may receive an email which seems coming from my preferred social network. This email opens a login page similar to my preferred social network. But with a different URL. With precaution, I directly close the browser. Nevertheless, something bad already happened. By clicking on the email link, a script was called. This script stole the session information of the social network and shared some sensitive information with the attacker. If it were a shopping website, the action could be buy something and send it to the attacker’s address. All of this just by clicking in the email link.

The CSRF Protection by Spring Security

Allowed Origins

So, to prevent all of this, I have multiple actions. The first one is to only authorize my trusted frontends to call my backend. Sprint Boot is prepared to have the frontend integrated inside the Spring Boot application, to have a server-side rendering. But this is not always the case. In my case, I have a React application, which is delivered from a separated server. This separated server has a different address. This is the only address that must be allowed to perform requests to my backend.

config.addAllowedOrigin("http://localhost:3000");

This will allow the preflight requests. Those are the OPTIONS requests. The OPTIONS request will check if the backend accepts requests from a given origin and for a given verb. Those requests are only sent for modification verbs: POST, PUT, DELETE or PATCH. And the response will contain the header Access-Control-Allow-Origin with the origin accepted. This means that I must also accept the OPTIONS method.

config.setAllowedMethods(Arrays.asList(
                HttpMethod.GET.name(),
                HttpMethod.POST.name(),
                HttpMethod.PUT.name(),
                HttpMethod.OPTIONS.name(),
                HttpMethod.DELETE.name()));

CSRF Token Repository

Let’s go now to the SecurityConfig where I’ve disabled the CSRF. As said, Sprint Boot enables it by default. So, let’s enable it again and configure it correctly.

http.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());

This way, I tell Spring to store the CSRF token in a cookie. Setting HTTP only to false, allows my frontend to access the value of the cookie. This cookie will be sent back at each request made to the backend. This ensures me that not only I’m the only front-end I’m performing requests to my backend, but that I’m the one which initiated the communication.

The CSRF Endpoint

This cookie will have an initial value at the beginning. And with each correctly received request, the value will change. This makes my communication unique. And the value of the cookie with a time range validity. Another option to store the token is in the session. But my application is currently a stateless application, so I must choose this option. And to get this initial token, I will need a controller. Let’s create this controller.

@RestController
public class CsrfController {

    @GetMapping("/v1/csrf")
    public CsrfToken csrf(CsrfToken token) {
        return token;
    }
}

From my frontend, I will need to call this endpoint to get my initial token. And this endpoint must be accessible without any authentication.

http.antMatchers(HttpMethod.GET, "/v1/csrf").permitAll();

To increase even more the security, this token must be sent in both the cookie and a header named X-XSRF-TOKEN. This way, my Spring Boot application will have two channels to validate the validity of the request: with the cookie and with the header. That’s why I will need to authorize this header.

config.setAllowedHeaders(Arrays.asList(
                HttpHeaders.AUTHORIZATION,
                HttpHeaders.CONTENT_TYPE,
                "X-XSRF-TOKEN",
                HttpHeaders.ACCEPT));

Conclusion

  • I must authorize only the trusted origins to request my backend.
  • I must enable the CSRF protection with the Cookie repository as I am in a stateless application.
  • I must accept the OPTIONS method and the XSRF header from my request.
  • And finally, I must create an additional controller to generate the first token.

References

Repository


Never Miss Another Tech Innovation

Concrete insights and actionable resources delivered straight to your inbox to boost your developer career.

My New ebook, Best Practices To Create A Backend With Spring Boot 3, is available now.

Best practices to create a backend with Spring Boot 3

One response to “The CSRF Protection with Spring Security”

  1. […] For simplicity, I disable the CSRF. You can find more information about the CSRF in the following link. […]

    Like

Leave a reply to Protect your Spring Boot application with JWT – The Dev World – Sergio Lema Cancel reply

Discover more from The Dev World - Sergio Lema

Subscribe now to keep reading and get access to the full archive.

Continue reading