CSRF Defence - Double Submit Cookie Pattern Demo

This is a continuation of previous csrf prevention tutorial. If you haven't read it, please read it first.

 Lets continue from previous one. As you can remember, we have succesfull implemented an application that prevents from csrf attacks using synchronizer token pattern. Today we will try to prevent csrf using double submit cookie pattern. Since both synchronizer token pattern and double submit cookie pattern have same application base, I will try to modify the previous application to achieve the goal.

Before the coding, lets remember the idea and difference between synchrizer token pattern and double submit cookie pattern. In synchronizer token pattern, server needs to maintain a list of csrf tokens for each user session. So client will request that stored token using an ajax request. Since cross domain requests are not allowed by default in ajax, malicous sites cannot request csrf token from server.

In double submit cookie pattern, server will not maintain list of csrf tokens. It just created token, send to client as a cookie and remove from memory. So csrf token will stored in client. When client communicating with server, client will send csrf cookie and same value within the body or header in the request. So in server, both csrf value in cookie and csrf value in body/header will compared and connection will be allowed only if both value are same. In order to send csrf token in body/header, client use javascript. Just read csrf value in cookie and copy it into body/header. So malicous site cannot do this since it is in a different domain. For example javascript in news.com cannot read cookies of welcome.com.

So there is a small modification to be done in order to make our prevous application to double submit cookie pattern. Lets open that application and start.

As the first step as you can remember, we don't need to maintain csrf tokens in server. So we can just remove SessionStore class and all objects of that.

Next modification is in RequestController class. You can find it in controller package. In double submit cookie pattern, we need to compare csrf token in cookie and header/body. So here we need to implement that logic.

package com.n256coding.crosssiterequestdscookiedemo.controller;
import org.springframework.web.bind.annotation.CookieValue;import org.springframework.web.bind.annotation.PostMapping;import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.util.Collections;import java.util.Map;
@RestControllerpublic class RequestController {

    @PostMapping(value = "/mydata")
    public Map<String, String> setInformation(@CookieValue("JSESSIONID") String sessionId,                                              @CookieValue("csrf_token") String csrfTokenInCookie,                                              HttpServletRequest request, HttpServletResponse response) {
        String csrfTokenInBody = request.getParameter("csrf_token");        String accountNumber = request.getParameter("receiver_account_number");        double value = Double.parseDouble(request.getParameter("value"));
        System.out.println("CSRF token in cookie: " + csrfTokenInCookie);        System.out.println("CSRF token in body: " + csrfTokenInBody);

        if (csrfTokenInBody == null || csrfTokenInCookie == null) {
            response.setStatus(403);    //Forbidden            System.out.println("CSRF tokens not matched, connection prevented");            return Collections.singletonMap("response", "forbidden");        }

        if (csrfTokenInBody.equals(csrfTokenInCookie)) {
            response.setStatus(200);    //Ok            System.out.println("CSRF tokens matched, connection allowed");            return Collections.singletonMap("response", "success");        } else {
            response.setStatus(403);    //Forbidden            System.out.println("CSRF tokens not matching, connection prevented");            return Collections.singletonMap("response", "forbidden");        }
    }

}

Now we need to modify logic in javacript. In javascript, we need to read cookie storage and retrieve csrf cookie. For that purpose, I have used js cookies library. So add

<script src="https://cdn.jsdelivr.net/npm/js-cookie@2/src/js.cookie.min.js"></script>

to home.html. Then replace script.js with code below.
$( document ).ready(function () {
    //Read cookie 'csrf_token' cookie from cookie storage and append into the form
    $('<input>').attr({
        type: 'hidden',        id: 'X-CSRFToken',        name: 'csrf_token',
        //read cookie named 'csrf_token' from cookie storage        value: Cookies.get('csrf_token')
    }).appendTo('form');});

$('#my_data_form').submit(function (event) {
    event.preventDefault();
    $.ajax({
        type : "POST",        url : "/mydata",        data :$(this).serialize(),        success : function (data, status) {
            console.log("Inside post");            if(status == "success") {
                if (data.response == "success") {
                    $("#form_response").html('Data has successfully recorded.');                }
                else if (data.response == "invalid") {
                    $("#form_response").html('Request forbidden. Nothing transferred.');                }
            }
            else{
                $("#form_response").html('Unknown error occurred. Try again');            }
            $('#informationModel').modal('show');        }
    });
});

$(document).ready function is a JQuery function that runs on page load. It will read cookie storage and grab value of cookie named 'csrf_token'. Then the value will be appended to html form as a new html hidden input element. 

Thats all!. Now this application is preventing csrf attacks using this double cookie submit pattern.

This is the end of this post. Feel free to ask any question about this on comment section. Completed application is available in my github repo. You can always refer it in case of any problem.

Github Project - https://github.com/n256Coding/cross-site-request-dscookie-demo

Comments

Popular posts from this blog

CSRF Defence - Synchronizer Token Pattern Demo

Lets read emails in gmail using oAuth 2.0 (Application demo)

How to view queries executed in MySQL?