Skip to main content

Preventing Cross Site Request Forgery Using Synchronizer Token Pattern


What is Cross Site Request Forgery?


Cross Site Request Forgery (CSRF) is an attack that forces an end user to execute unwanted actions on a web application in which they are currently authenticated. CSRF attacks specifically target state- changing requests. With a little help of social engineering like sending a link through an email or a chat, an attacker can trick a user of a web application into executing actions of the attacker’s choosing. Depend on the user type that the attacker is targeting the damage that can be caused by CSRF may differ.

CSRF is an attacker tricks a user into submitting a malicious request which inherits the identity and privileges of the victim to perform an undesired function on the victim’s behalf. Most of the sites and browser requests automatically include any credentials associated with the site such as the user’s session cookie, IP address, windows domain credentials and so on.
When you click on a link a web page, your browser sends a request to the web server. Such requests can broadly be categorized into two types: GET and POST.  A GET request is simply a request for a page and a POST request is sent when you need to send data to the sever.

Objectives of CSRF attacks

An application that allows a user to send or update data is a potential target for an attacker. The following is a list of potential uses for CSRF:
  • Transfer money from one bank account to another bank account.
  • Use a content management system to add or delete content from a website
  • Change a user’s password
  • Add items to a use’s shopping cart list

A CSRF attack example

Imagine a website allows their uses to login using their emails and the site contains a page called “my account” that will store all the information of the user and often allows a user to change to his/her email address. This email address change could either be made as a POST request or as a GET request. It is possible for an attacker to forge this request once he or she knows the structure of it, and discovering the structure is simple, especially if users can register their own accounts.
According to the example below, the data to be changed is contained in a parameter called “EmailAdress”. If the user can be tricked into visiting a website which is under the attacker’s control, the following code can be used to change the email address stored as a login credential on that particular site:

<html>
<body>
<H1> Hello</'H1>
<img src="http://examplesite.cpm/MyAccount?EmailAddress=emailaddress@site.com" width ="1" height="1"/>
</body>
</html>

The page can be presented as anything or either it could be a blank page or else it could be a replica of the site that is under the attack. All it needs is the above code which displays the image and the image does not need to exist. As soon as the user’s browser starts to load the page the code will get executed and automatically submit the request to change the user’s email address. As long as the user is logged into the site this scenario will proceed as the victim has clicked the link.

Even if the website only allows updates via POST, it is possible to change the email address in the same way and it requires some different code:

<html>
<body>
<form name="CSRF", method="POST", action="http://examplesite.com/MyAccount?EmailAddress=emailaddress@site.com">
<input type='hidden' name='EmailAddress' value='http://examplesite.cpm/MyAccount?EmailAddress=emailaddress@site.com'>
</form>
<script> document.CSRF.submt()</script>
</body>
</html>

In both cases, once this is submitted, the email address is automatically changed. Then it is simple as using the built-in password-rest facility that most websites have. If this sends the password directly to the registered email address, the password will them be mailed to the attacker and the user account is compromised.



How to defeat CSRF

There are 2 types of patterns that systems can adapt in order to prevent CSRF on any website.  
  1. Synchronizer Token Pattern
  2. Double Submit Cookie Pattern

In this blog we will look at how these two types of patterns prevent CSRF and how it can be implemented in a Java application.

Synchronizer Token Pattern

Synchronizer Token Pattern is a very simple concept to mitigate the risk of being attacked through CSRF. It is a technique where a token, secret and unique value for each request is embedded by the web application in all HTML forms and verifies on the server side.

When a request is made to the server to change data, the server code will read and validate the token’s origin. If the server cannot read the token, it is likely that the token was not issued by the server and the request should not be processed.
The token could be generated using any method which ensures the uniqueness (either by using hash chain of random seed) and because of this the attacker will not be able to place a token in their requests to authenticate them.

Let’s see how we can implement this. I have included the details of the project that I implemented to  demonstrate. You can access the project through my GitHub account :


This project is done using Java servlet and JSP. In here for demonstrating synchronize token 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 texts 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 {
       
        // get username and password form request
        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. That CSRF value and corresponding session id will be stored that in HashMap which is available in the Token class. Once all the process completed it will redirected to the welcome.jsp.



Note:- HashMap has used for the simplicity of  this blog. Otherwise it need to use database in order to store the session id and corresponding CSRF id.

3. Token.java

package Models;
import java.util.Date;
import java.util.HashMap;

public class Token {

    private static String csrf;
    private static String sesssion;
    private static HashMap<String,String> sessionMap = new HashMap<String, String>();

    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;
    }

    public HashMap<String, String> getSessionMap() {
        return sessionMap;
    }

    public void setSessionMap() {
        Token.sessionMap.put(this.sesssion, this.csrf);
    }
   
}


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

4. Feedback page



5. Welcome.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>Message</title>
    </head>
    <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="message"/>
            </div>
            <form action="ValidateData_syncronizeToken" 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>
                        <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() {

            $.ajax({
                type: "GET",
                url: "http://localhost:8080/csrfDemo/CsrfIssuer",
                contentType: "text/json",
                success: function (data) {
                    $("#submit-btn").before('<input type="hidden" name="csrf" value="' + data + '">');
                },
                error: function (err) {
                    console.log(err);
                }
            });
        }
    </script>

</body>
</html>


Once welcome.jsp  page loaded, it will call automatically call AJAX get request for CsrfIsssuer.java class and it will return the CSRF id relevant to current session. Once the CSRF id has received, that value set to the hidden filed in the form.

6. AJAX call

$.ajax({
    type: "GET",
    url: "http://localhost:8080/csrfDemo/CsrfIssuer",
    contentType: "text/json",
    success: function (data) {
        $("#submit-btn").before('<input type="hidden" name="csrf" value="' + data + '">');
    },
    error: function (err) {
        console.log(err);
    }
});

Once after this form submitted, feedback values will be redirected to the ValidateData_syncronizeToken.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 is available for current session id. If it is matched we can ensure that this request is exactly the same response which has sent from the front end.

6. ValidateData_syncronizeToken.java (servlet)

package servlet;
import Models.Token;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

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

    Token tkn = new Token();

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        //get current session id
        String currentSID = tkn.getSesssion();
       
        HttpSession session = request.getSession();
       
        tkn.getSessionMap().entrySet().forEach((m) -> {
            if (m.getKey().equals(currentSID)) {

                if (request.getParameter("csrf").equals(m.getValue())) {
                    session.setAttribute("result_value", "Your responce has been ensured with CSRF sysncronize token pattern!");

                } else {
                    session.setAttribute("result_value", "Your responce is recoded but not ensured with CSRF");
                }
            }
            System.out.println(m.getKey() + " - " + m.getValue());
        });

        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 response has been ensured with CSRF synchronize token pattern!’) in a session variable, and show that in the result page (result.jsp)



7.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...