[JAVA] CSRF countermeasure policy and implementation example in REST application using "Spring Boot" + "EXT JS"

Since there was little information on the above combinations, I summarized it.

Countermeasure policy

As a measure against CSRF (cross-site request forgery), we use a general token issuance method. It is easy to use Set-Cookie to notify the token information from the server to the client. Spring Boot will do it for you. [^ 1] Token transmission from client to server is written independently in JavaScript, and cookie information is written in http header except for GET request [^ 2].

[^ 1]: Even if you pass the token with a cookie (by mistake at first), the browser will send it without permission as if you had the session ID with a cookie, so it is meaningless as a CSRF measure? I thought, but when checking the CSRF token in Spring Boot, it is not looking at the cookie value, but looking at "_csrf of form data" or "X-XSRF-TOKEN of http header". It was a miso. It is necessary to replace the token from cookie to form data or http header, but this is not possible with cross-origin JS (you can not see the cookie of the legitimate domain), so it is a countermeasure.

[^ 2]: Considering the characteristics of CSRF attacks, it is not necessary to verify with a GET request. Spring Boot does not do server-side checks.

  1. Spring Boot
    1.1. Set the CSRF token storage destination as a cookie. 1.2. Not HttpOnly to allow access from JS.
  2. Ext JS
    2.1. GET requests are excluded. 2.1. Obtain token information from cookie value when sending Ajax request with Ext and add it to Http header.

Implementation example

Spring Boot
CSRF measures are enabled by default, but the token storage destination is specified and httpOnly is disabled.

SecurityConfig.java



public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
            .and()
            ...//Omitted. Define the necessary definitions as appropriate.
    }
}

Ext JS
Since it is necessary to give tokens to all requests skipped by Ajax, it is defined in the place called higher. By defining it as "beforerequest", processing is performed before issuing an Ajax request so that it does not have to be implemented individually.

app.js


Ext.Ajax.on('beforerequest', function (conn, request, eOpts) {
    //Grant CSRF token in cases other than GET request.
    if (request.method === 'GET') {
        return;
    }
    //Cookie XSRF-TOKEN item value, arbitrary http header X-XSRF-Grant as TOKEN.
    if (document.cookie) {
        var cookies = document.cookie.split(";");
        for (var i = 0; i < cookies.length; i++) {
            var str = cookies[i].split("=");
            if (str[0] == 'XSRF-TOKEN') {
                conn.setDefaultHeaders({ 'X-XSRF-TOKEN': unescape(str[1]) });
                break;
            }
        }
    }
});

Recommended Posts

CSRF countermeasure policy and implementation example in REST application using "Spring Boot" + "EXT JS"
Implement REST API with Spring Boot and JPA (Application Layer)
Get error information using DefaultErrorAttributes and ErrorAttributeOptions in Spring Boot 2.3
Spring Boot application development in Eclipse
Uploading and downloading files using Ajax in Spring Boot (without JQuery)
Implement REST API in Spring Boot
Implement Spring Boot application in Gradle
Implementation of category selection form using JS in flea market application creation
Automatically deploy a web application developed in Java using Jenkins [Spring Boot application]
Using Hystrix and Sentinel in code example
[FCM] Implementation of message transmission using FCM + Spring boot
Output request and response log in Spring Boot
Create a Spring Boot application using IntelliJ IDEA
Create a portfolio app using Java and Spring Boot
Testing JPA entities and repositories using Spring Boot @DataJpaTest
Spring Boot application built-in Tomcat, Apache and WebSocket integration
Try using DI container with Laravel and Spring Boot
Try using OpenID Connect with Keycloak (Spring Boot application)
Test field-injected class in Spring boot test without using Spring container
Introduce swagger-ui to REST API implemented in Spring Boot