Adam_O
Adam_O

Reputation: 341

CSRFGuard: How to inject CSRF token into URL returned by AJAX call

We are attempting to add CSRF protection to our existing java web application by using CSRFGuard. We've followed the OWASP's guide to token injection, and that has gotten us most of the way there. We're using the dynamic DOM manipulation method, and find that most URLS/forms/AJAX calls are properly formatted with the inserted CSRF token. Our issue is this:

Parts of some pages are generated dynamically by AJAX calls that return jspfs. The jspfs that are returned have links which were never subject to the CSRFGuard DOM Manipulation, and as such, don't have the CSRF token. Clicking on those links causes a CSRF violation because no token is present.

Furthermore, according to the OWASP guide for AJAX support, the dynamic script needs to be reference prior to the AJAX call so that the AJAX call can be intercepted and have the CSRF token inserted into the header. This is the same script that dynamically updates the DOM. So - to solve the issue posed in this question I would need to run the script after the AJAX call, but I also need to run it before the AJAX call to make it in the first place. Trying to run it twice causes issues.

What is the proper solution here? Does that CSRFGuard javascript file need to be modified so that dynamic token injection can be run against targeted elements? Has this issue been solved already?

Upvotes: 1

Views: 3954

Answers (2)

Gabriel Bratescu
Gabriel Bratescu

Reputation: 419

I had the same problem. I modified csrfguard.js this way:

  1. I moved out all functions from (function() {}) block and put them before the block.
  2. I defined 2 new functions

        function getTokenNameValuePair() {
            var xhr = window.XMLHttpRequest ? new window.XMLHttpRequest : new window.ActiveXObject("Microsoft.XMLHTTP");
            var csrfToken = {};
            xhr.open("POST", "%SERVLET_PATH%", false);
            xhr.setRequestHeader("FETCH-CSRF-TOKEN", "1");
            xhr.send(null);
            return xhr.responseText;
    } 
    
    function injectTokensForNewTags() {
        var token_pair = getTokenNameValuePair();       
        token_pair = token_pair.split(":");
        var token_name = token_pair[0];
        var token_value = token_pair[1];
        injectTokens(token_name, token_value);
    }
    

And your AJAX that is returning a HTML chunk with links should look like this:

    $.post(loadurl, function(data) {
        $(target).html(data);
        injectTokensForNewTags();
    });

Upvotes: 2

DSoa
DSoa

Reputation: 793

Note: this answer requires modifying CSRFGuard.

I am using SkateJS (https://github.com/skatejs/skatejs) to watch for dynamic updates of <a>, <img>, and <form> tags and calling a routine I added to csrfguard.js to add the token to them.

This catches tags that are inserted after the initial DOM load by javascript toolkits.

I had to also modify the script to keep it from always scanning the entire DOM tree at load time to insert the tokens. This was very inefficient and was unnecessary with the above method.

Here's an example of the SkateJS config:

window.addEventListener('load',
    function() {
        var config = {
            ready : function(element) {
                if (CsrfGuard && CsrfGuard.isEnabled) {
                    CsrfGuard.injectTokens([element]);
                } else {
                    skate.destroy();
                }
            },
            type : skate.types.TAG
        };
        skate('a', config);
        skate('img', config);
        skate('form', config);
    }
);

Note: this will not work on IE8. For that, I am using Microsoft DHTML behaviors.

<![if IE 8]>
<style>
a,img,form {
    behavior: url("csrf_ie8.htc");
}
</style>
<![endif]>

csrf_ie8.htc:

<public:attach event="ondocumentready" onevent="CsrfGuard.injectTokens([element]);" />

Upvotes: 0

Related Questions