"Encountering issues with CSRF token validation in an Angular SpringBoot application when making an Ajax POST request, resulting in an

Current Project Details

The ongoing project involves developing a single-page Angular JS application using SpringBoot with a Spring Security implementation. The application, known as 'Study Planner', allows students to input their study leave on a calendar. Progress has been made on enabling students to log in and enter details client-side.

Development Focus

Currently, the main focus is on capturing the added events in our client-side JavaScript and sending them back to the server using an Ajax POST request. The goal is to then store this data in the database tied to the student, enabling it to be retrieved when the student accesses the calendar in the future.

Challenges Faced

The primary challenge encountered revolves around the Ajax POST method, specifically due to the inclusion of a CSRF header in an attempt to bypass Spring Security. When the csrf header is absent, a 403 (unauthorized) error is triggered. However, upon introducing the csrf header, no network traffic is recorded, the server is not contacted, and the "error" function in the Ajax call is activated.

Issue with CSRF Token

https://i.sstatic.net/pDq7z.jpg

  1. Student Logs in to their Calendar
  2. Student adds an event
  3. 'newEventData function' alert triggered
  4. 'we failed' alert triggered
  5. 403 Error in Chrome

    403 (Forbidden) "Invalid CSRF Token 'null' was found on the request parameter '_csrf' or header 'X-XSRF-TOKEN'."

Resolution Attempts

https://i.sstatic.net/7vB9C.jpg

Despite adapting documentation from Spring to include the csrf token within 'beforesend', the issue remains. The same outcome occurs if the function from the docs is simply appended at the end of the JavaScript file.

  1. Student Logs in to their Calendar
  2. Student adds an event
  3. 'newEventData function' alert triggered
  4. 'beforesend' alert triggered
  5. 'we failed' alert triggered
  6. Error thrown

    SyntaxError: Failed to execute 'setRequestHeader' on 'XMLHttpRequest': '$(_csrf.headerName}' is not a valid HTTP header field name.

Seeking Assistance

  • How can more detailed information about the Ajax error be obtained?
  • What might be causing the absence of network traffic despite the Ajax call resulting in an error?
  • Any recommendations for configuring Spring Security to mitigate this issue, aside from disabling it completely?

Additional Information

  • The WebSecurityConfigAdapter has been extended
...Code snippet here...
  • Extension of 'OncePerRequestFilter' implemented (However, no System Outs are printed during the Ajax POST)
...Code snippet here...
  • The method being targeted is not being accessed when the csrf security is active within HttpSecurity
...Code snippet here...

Apologies for the lengthy description, but the issue has been challenging, especially given the complex nature of web application security. Any guidance or suggestions on resolving this dilemma would be highly appreciated.

Thank you, Scott.

Update on Error Handling

Following the inclusion of error parameters as suggested by Paqman, additional information has been gathered, yet the resolution strategy remains uncertain.

SyntaxError: Failed to execute 'setRequestHeader' on 'XMLHttpRequest': '${_csrf.headerName}' is not a valid HTTP header field name.

https://i.sstatic.net/keejZ.jpg

When inspecting the chrome console, it seems that these values are being treated as text variables. Is this the incorrect approach? https://i.sstatic.net/4vrKB.jpg

Within index.html, the code snippet within the header section is as follows:

...Code snippet here...

Additional Update

The issue concerning literal string problems was resolved by using 'th:content' instead of 'content', yet errors persisted regarding the undefined nature of the header/token. The actual solution to this problem has been shared, but for others facing similar challenges with accessing metadata in HTML files in an Angular project, changing 'content' to 'th:content' may prove beneficial.

View this related question

...Code snippet here...

Answer №1

After encountering a lot of confusion, we were able to successfully resolve the issue at hand. Contrary to most of the documentation I came across which indicated that the csrf token was stored in the session, our application actually deviates from the default SpringSecurity behavior by storing it in a cookie. This approach was adapted from the SpringBoot Angular Guide.

 public class CsrfHeaderFilter extends OncePerRequestFilter {

/**
 * Overrides SpringSecurity filter
 */
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
        throws ServletException, IOException {
    CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
    if (csrf != null) {
        System.out.println("csrf is null");
        Cookie cookie = WebUtils.getCookie(request, "XSRF-TOKEN");
        String token = csrf.getToken();
        if (cookie == null || token != null && !token.equals(cookie.getValue())) {
            cookie = new Cookie("XSRF-TOKEN", token);
            cookie.setPath("/");
            response.addCookie(cookie);
        }
    }
    filterChain.doFilter(request, response);
  }

Initially, we were led astray by following the guidance in the Spring Docs here due to this configuration.

Upon realizing this, we found valuable insights in the Django docs which directed us towards extracting the token value from the cookie.

Solution

We incorporated the following JavaScript function to retrieve the token:

function getCookie(name) {
    var cookieValue = null;
    if (document.cookie && document.cookie != '') {
        var cookies = document.cookie.split(';');
        for (var i = 0; i < cookies.length; i++) {
            var cookie = jQuery.trim(cookies[i]);
            // Does this cookie string begin with the name we want?
            if (cookie.substring(0, name.length + 1) == (name + '=')) {
                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                break;
            }
        }
    }
    return cookieValue;
}

Subsequently, we assigned the returned value from this function to a variable:

 var csrftoken = getCookie('XSRF-TOKEN');

Finally, we hardcoded (uncertain of potential issues in the future) the HEADER and utilized the earlier declared variable for the token:

function newEventData(ev) {
    $.ajax({
        "url" : "/Student/" + loggedinusername
                     + "/universitydays?id=" + ev.id + "&text="
                     + ev.text + "&start="
                     + Date.parse(ev.start_date) + "&end="
                     + Date.parse(ev.end_date),

        "method" : "POST",
        beforeSend : function(xhr) {
              xhr.setRequestHeader("X-XSRF-TOKEN", csrftoken);
        },
        "success" : function() {

        },
        "error" : function(jqXHR, textStatus, errorThrown) {
              alert("error: " + errorThrown);
        } 
 });

}

We hope this explanation proves beneficial to others facing a similar challenge.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Tips for using the arrow keys to navigate the cursor/caret within an input field

I am trying to create a function that allows the cursor/caret to move inside an input field character by character using the arrow keys (ArrowLeft, ArrowRight) on a keydown event. Current Approach: const handleKeyDown = (e: KeyboardEvent<HTMLInputEle ...

Execute a particular NodeJS function within the package.json scripts section

I've got a NodeJS file with an export function that looks something like this: test.js exports.run = function(){ console.log('You execute this function!'); }; Is there a way to trigger this function specifically by using a custom comman ...

Implementing atomic design principles in Vue 3 with TypeScript

I'm currently implementing atomic design principles in my Vue application. Here is the code for my button atom: <template> <ElButton :type="button?.type" :plain="button?.plain" :rounded="button?.rounded ...

What is the possible reason behind the Vue warning message: "The instance is referencing the 'msg' property or method during rendering, even though it is not defined"?

Although the situation seems straightforward, the reason behind it is not clear to me. I am attempting to create a Vue component for a project with older ES5 code. The Vue library version I am using is 2.6x (I also tried 2.5x). Here is the Vue component I ...

jquery accordion not functioning properly following partial ajax page refresh

Initially, I'm using a jQuery accordion that works perfectly. However, I encounter an issue when implementing some Ajax commands to reload part of the page, specifically the inner body section. After the page reloads, the accordion breaks because the ...

I am experiencing a 404 error when attempting to import a local JS file in Angular

After creating a new project with "ng new xxx", all you need to do is add one line of code in index.html: <!doctype html> <html lang="en> <head> <meta charset="utf-8> <title>Bbb</title> <base href="/&g ...

How to retrieve the value of an observable from a regular JavaScript array in Knockout JS?

Context In my project, I am working with a plain JavaScript array that starts off empty but gets populated with Knockout observables later on. These values are numbers and I need to compare them with values in another Knockout observable array. The issue ...

Having trouble integrating RGraph into my HTML page with AJAX

As I work on developing a simple webpage layout with both a static header and footer, I'm encountering some challenges in updating content dynamically. The left side menu triggers an ajax request when clicked, which should update the text on the right ...

Encountering an error in React Native: Unable to access property 'length' as it is

Currently, I am working on developing a registration application and I have encountered some issues in the final phases when attempting to submit the new data to the server. Below is the script I am using: import React from 'react'; import React ...

I'm seeking some assistance in resolving my JavaScript issue

Let's create a function known as 'bigOrSmall' that requires one parameter, 'arr', which will contain an array of numbers. Inside the 'bigOrSmall' function, let's define a new array named 'answers'. Next, it ...

What's the CSS equivalent of Java's window.pack() method?

I'm relatively new to css and I'm attempting to create a border around a <div>. My goal is for the border to be limited to the size of the elements inside the div and adjust dynamically in proportion to any new objects that may appear or di ...

Challenges arise in compiling JS with webpack due to spread syntax complications within an npm package

In my code, I have a class called AnalyticsService with methods for logging analytics events to Google Analytics and Kentico. When trying to reuse this code in different projects by importing it from an npm package, I encountered a compile error related to ...

Crop and upload images asynchronously using Node.js

I need to resize an image into multiple sizes and then upload them to AWS S3. The specific resizing dimensions are stored in an array. To accomplish this, I am utilizing the async waterfall method along with the series method. async.each(crop_sizes, func ...

Using Sequelize to update all values in a JSON file through an Express router.put operation

I've been working on a feature in my Express router that updates data in a MySQL schema for 'members' of clubs. The members table has various columns like member_id, forename, surname, address, etc. I've successfully created an Express ...

An unexpected 'undefined' occasionally tacked onto 1% of the URLs visitors requested on my website starting from June 12, 2012

Ever since June 12, 2012 at 11:20 TU, I have been noticing strange errors in my varnish/apache logs. At times, after a user has requested a page, I observe a similar request moments later but with the URL string after the last "/" being replaced by "undef ...

Breaking down an array in Node.js

After web scraping, I retrieved an array structured like this: array: [ 'line1', 'line2', 'line3', 'linen'.. ] My task now is to insert this data into a MySQL table. The challenge is that every 10 lines of ...

Numerous Levels of Dropdown Menus

I am looking to implement a feature on a web page where users can select multiple vehicles using JQuery. The idea is that selecting the brand in the first dropdown will populate the second dropdown with the models available for that specific brand. The ...

Bypassing CORS in angularjs without server-side access

I am facing a challenge in retrieving JSON data from my AngularJS (v1) client website. This is the code I am using: $http.get('https://usernamexx:<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="d9a9b8aaaaa1a199bbb8bab2bcb7 ...

When should ng-repeat be utilized: only when the object type is an array?

I have a detailed object structure below: $scope.document = { "GENERAL_FIELDS": { "Source_Type": "custom", "Annotations": [ "216/content/Factiva_CM_001/Proteins", "216/content/Factiva_CM_001/Fact" ], "Content": [ " ...

I possess a JSON array object and need to identify and extract the array objects that contain a specific child node

const jsonArray = { "squadName": "Super hero squad", "homeTown": "Metro City", "formed": 2016, "secretBase": "Super tower", "active": true, "members": [ { "name": "Molecule Man", "age": 29, "secretIdent ...