Skip to main content

Preventing Cross Site Request Forgery Using Double Submit Cookie Pattern


What is Cross Site Request Forgery?

Previously we discussed about what is CSRF and what are the potential CSRF, objectives of CSRF and an example for a possible CSRF attack. Also, I shared some information about the project I implemented to demonstrate the Synchronized Token Pattern.
To read more please visit my previous blog post from here: 

https://kmbloggerz.blogspot.com/2018/10/preventing-cross-site-request-forgery.html

In this blog post, I will be discussing about the second pattern of preventing CSRF attack, which is Double Submit Cookie Pattern.

Double Submit Cookie Pattern

This is defined as sending a random value in both cookie and as a request parameter, with the server verifying of the cookie value and request value are equal. When a user authenticates to a site, the site should generate a cryptographically strong value and set it as a cookie on the user’s browser separated from the session id.
The site does not need to save he session id. Then the site should require every sensitive submission to include this random value as a hidden form of value on the request parameter and also as a cookie value.
Because of this, an attacker will not be able to read and modify any data that sent from the server. This means that while an attacker can send any value he/ she wants with a malicious CSRF request, but the attacker will not be able to read and modify the data stored in the cookie. Since the cookie value and the request parameter value must be the same, therefore, the attacker will not be able to successfully submit a form unless he is able to guess the random CSRF value.

How can we implement Double Submit Cookie Pattern in an application?

you can access the whole project in my GitHub from here: 

https://github.com/KMKasunMadusanka/CSRF_JAVA_Double_Submit_Cookie_Pattern

Let’s see how we can implement this project:
This project is done using Java servlet and JSP. In here for demonstrating double submit cookie pattern. It uses 3 simple interfaces (login, form and result page). 
For this demo following code structure has been used.



In order to handle the font-end of the login page it uses JSP page and all the functionalities of that page will handle in the separate servlet page.
 First we will look into the login page.



1.       login.jsp
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
    <head>
        <!--Style Sheet-->
        <link rel="stylesheet" href="./resources/login.css"/>

        <!--Bootstrap-->
        <link href="//maxcdn.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css" rel="stylesheet" id="bootstrap-css">
        <script src="//maxcdn.bootstrapcdn.com/bootstrap/4.1.1/js/bootstrap.min.js"></script>
        <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>

        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Login</title>
    </head>
    <body id="LoginForm">
        <div class="container">
            <h1 class="form-heading">SLIIT Feedback Collection Page</h1>
            <h5 class="form-heading_h5">Secured with double submit cookie pattern</h5>
            <div class="login-form">
                <div class="main-div">
                    <div class="panel">
                        <h2>System Login</h2>
                        <p>Please enter user name and password</p>
                    </div>
                    <form id="Login" action="login" method="post">
                        <div class="form-group">
                            <input type="text" name="username" class="form-control" id="username" placeholder="User Name">
                        </div>
                        <div class="form-group">
                            <input type="password" name="password" class="form-control" id="password" placeholder="Password">
                        </div>
                        <div class="forgot">
                        </div>
                        <button type="submit" class="btn btn-primary">Login</button>
                    </form>
                </div>
            </div>
        </div>
    </div>
</body>
</html>


In the login.jsp it has two text and once your submit the username and password values, relevant data will redirected to the login.java (servlet page) as a post request.

Note :- Do not use GET request for these kinds of secure data transformation operations. In the GET request, it shows all the values of each and every variable in the form as URL parameters.

Then after, we will consider about logic which has implemented in the login.java servlet page.

2.       Login.java (servlet)
package servlet;
import Models.Token;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(name = "login", urlPatterns = {"/login"})
public class login extends HttpServlet {

    Token tkn = new Token();

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        String username = request.getParameter("username");
        String password = request.getParameter("password");

        if (username.equals("admin") && password.equals("admin")) {

            Cookie[] cookies = request.getCookies();
            if (cookies != null) {
                for (Cookie cookie : cookies) {
                    if (cookie.getName().equals("JSESSIONID")) {

                        // set session id
                        tkn.setSesssion(cookie.getValue());
                    }
                }
            }
            // set session cookie
            Cookie sessionCookie = new Cookie("sessionID", tkn.getSesssion());
            response.addCookie(sessionCookie);

            // set cookie to username
            Cookie usernameCookie = new Cookie("username", username);
            response.addCookie(usernameCookie);

            // create csrf token
            tkn.setCsrf();

            // set session cookie
            Cookie csrfCookie = new Cookie("csrf", tkn.getCsrf());
            response.addCookie(csrfCookie);

            response.sendRedirect("request.jsp");

        } else {
            response.sendRedirect("login.jsp");
        }

    }
}



In the beginning it has retrieve the corresponding values of the ‘username’ and ‘password’ from the request object.  Then it checks whether username and password values are matched with system provided username and password.

Assume: - I have assume that username and password for this system is admin, admin.

If the entered username and password is incorrect, then page will again redirect to the login.jsp. Otherwise it will store the current session id in the Token class and a separate cookie. In addition to that, username stored in a separate cookie for farther reference.  Then after CSRF token (random token) will be generated. Then after CSRF token store in a cookie. Once all the process completed it will redirected to the welcome.jsp.

3.       cookies


4.       Token.java
package Models;
import java.util.Date;

public class Token {

    private static String csrf;
    private static String sesssion;
   
    public String getCsrf() {
        return csrf;
    }

    public String getSesssion() {
        return sesssion;
    }

    public void setCsrf() {
        Date date = new Date();
        long timeinMiliSeconds = date.getTime();
        Token.csrf = Long.toString(timeinMiliSeconds);
    }

    public void setSesssion(String sesssion) {
        Token.sesssion = sesssion;
    }
}


After successfully logged in to the system, it will redirect to the feedback page (request.jsp)

5.       Feedback page




6.       Request.jsp
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
   
     <!--Style Sheet-->
    <link rel="stylesheet" href="./resources/welcome.css"/>
   
    <!--Bootstrap CSS Framework-->
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
    <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>

    <!--JQuery-->
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <script src="http://malsup.github.com/jquery.form.js"></script>
   
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Book Request</title>
    </head>
    <body>
    <body>  
        <div class="container contact-form">
            <div class="contact-image">
                <img src="https://cdn0.iconfinder.com/data/icons/social-messaging-ui-color-shapes/128/chat-circle-blue-512.png"  alt="rocket_contact"/>
            </div>
            <form action="ValidateData_doubleSubmitCookie" method="post">
                <h3>Drop Us a Message</h3>
                <div class="row">
                    <div class="col-md-6">
                        <div class="form-group">
                            <input type="text" name="txtName" class="form-control" placeholder="Your Name *" value="" />
                        </div>
                        <div class="form-group">
                            <input type="text" name="txtEmail" class="form-control" placeholder="Your Email *" value="" />
                        </div>
                        <div class="form-group">
                            <input type="text" name="txtPhone" class="form-control" placeholder="Your Phone Number *" value="" />
                        </div>
                       
                        <input type="hidden" name="csrf" id="hidden_input" value="">
                       
                        <div class="form-group">
                            <input type="submit" name="btnSubmit" class="btnContact" value="Send Message" id="submit-btn"/>
                        </div>
                    </div>
                    <div class="col-md-6">
                        <div class="form-group">
                            <textarea name="txtMsg" class="form-control" placeholder="Your Message *" style="width: 100%; height: 150px;"></textarea>
                        </div>
                    </div>
                </div>
            </form>
        </div>
    </body>
   
    <script>
    window.addEventListener('load', function() {
        console.log('All assets are loaded');
        retrieveToken();
    });
    function retrieveToken() {
       
        let cookieArray = document.cookie.split(';');
        console.log(cookieArray);
        for(let i = 0; i < cookieArray.length ; i++){
            if(cookieArray[i].split('=')[0] === ' csrf'){
                document.getElementById("hidden_input").value = cookieArray[i].split('=')[1];
            }
        }
    }
</script>

</body>
</html>


Once request.jsp page loaded, CSRF id which has set to cookie in the login page will be set as the value of hidden field in this page.

Once after this form submitted, feedback values will be redirected to the ValidateData_doubleSubmitCookie.java (servlet) class. In that class, it check the values of the hidden field which has set is exactly similar to the CSRF id which has set in the cookie. If it is matched we can ensure that this request is exactly the same response which has sent from the front end.

7.       ValidateData_doubleSubmitCookie.java (servlet)
package servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

@WebServlet(urlPatterns = {"/ValidateData_doubleSubmitCookie"})
public class ValidateData_doubleSubmitCookie extends HttpServlet {

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        String csrf_form = request.getParameter("csrf");
        Cookie[] cookies = request.getCookies();
        if (cookies != null) {
            for (Cookie cookie : cookies) {
                if (cookie.getName().equals("csrf")) {

                    HttpSession session = request.getSession();
                    // check the responce csrf is equal with server csrf
                    if (cookie.getValue().equals(csrf_form)) {
                        session.setAttribute("result_value", "Your responce has been ensured with CSRF Double submit cookie pattern!");
                    } else {
                        session.setAttribute("result_value", "Your responce is recoded but not ensured with CSRF");
                    }
                }
            }
            response.sendRedirect("result.jsp");
        }
    }
}

If the CSRF id which has stored in the backend is matched with CSRF id which has send from the front end it will store a status (‘Your responce has been ensured with CSRF Double submit cookie pattern!’) in a session variable, and show that in the result page (result.jsp)

8.       Result page

Result.jsp

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
    <head>
        <!--Style Sheet-->
        <link rel="stylesheet" href="./resources/result.css"/>

        <!--Bootstrap CSS Framework-->
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
        <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
        <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>

        <!--JQuery-->
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
        <script src="http://malsup.github.com/jquery.form.js"></script>

        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Result</title>
    </head>
    <body>
        <div class="title">
            Thank You For The Feedback
        </div>

        <%
            session.getAttribute("result_value");
        %>
       
        <div class="msg_cover">
            <div> Your Feedback has been successfully recoded! </div>
            <div class="msg"> ${result_value}</div>
            <a type="button" class="btn btn-info" href="http://localhost:8080/csrfDemo/">Home</a>
        </div>
    </body>
</html>





Comments

Popular posts from this blog

Handle MongoDB with WebStorm in Windows

Normally MongoDB is handle by using Windows command line interface. But it is little bit difficult to deal with. Therefore instead of Windows CMD,   we can use WebStorm Terminal to handle the MongoDB commands and all the stuff. First of all there should be two requirements to begin with this process. MongoDB should be properly install to the computer and MongoDB bin folder path should be set as environment variable. WebStorm should be completely install to your machine.(download link:- https://www.jetbrains.com/webstorm/download/#section=windows) There are simple three steps to do . install Mongo Explorer plugin to the Webstorme IDE                  + Open the WebStorm IDE and create an empty project                  + Go to Files >Settings>Browse repositories.                  + Search for 'Mongo' an...

Introduction to AngularJS for beginners.

AngularJS is a framework developed from the JavaScript for front-end developments of a web application. It allows us to create web application with dynamic behaviors. AngularJS follows MVC (Model View Controller) architecture and it has an amazing feature called 'two way data binding'. That means changers that are done to the HTML content will appear real-time to the script and changers that are done for the script will appear to the HTML content instantly. There are more reusable inbuilt components available with Angular and those components will give very attractive features to any web or mobile application. Because of its re-usability and easiness we can create any dynamic web application within few minutes. There are many versions available in Angular. Recently they released Angular 4.0 stable version to the community.  Angular 2.0 and 4.0 are little bit similar to each other. But Angular 1.0 is completely different with above versions. It is the oldest versi...

Robotic Process Automation

Introduction Robotic process automation is very important Technology in future world. This technology can be use to any kind of Business. By using the RPA, day to day repetitive business  tasks can be automated using software robots. Most of business use this technology because they can maintain good productivity and accuracy of their business process because of this. There are many tool available in the world to do the RPA. Among those tools Accello is very powerful automation tool implemented by VirtusaPolaris. By using this tool any kind of business process can be automated.Mainly it can do desktop automation and web automation using this tool. In addition to that various kind of automation are available in this tool.  This tool uses Java and JavaScript to handle the back-end of the application and AngularJS is used for the front-end.  OrientDB  is used as the database. It is powerful No-SQL graph database. Because of these new technologies many b...