CSRF & Double Submit Cookies

As I mentioned in my previous blog post about CSRF & Synchronizer Tokens, we can mitigate Cross Site Request Forgery AKA CSRF also by the technique called "Double Submit Cookies".
In here, the basic thing happens is, the server generates the CSRF token and set it as a cookie in the browser (need to specify the domain address), as well as the server will create the session cookie with the value of the session id. This whole thing happens when the event of a user login.
When a state changing request occur, the web page will get the CSRF cookie and add its value to a hidden field in the HTML DOM, same as the Synchronizer token pattern.
When the event of the authorization, server will validates the cookie value of the CSRF cookie with the received token value from the DOM.
This way we can prevent CSRF attacks from occurring using the "Double Submit Cookies pattern"

Attackers cannot perform a CSRF attack because, they need the token to do it obviously, and the cannot obtain the token cookie because javascript or any other script cannot retrieve cookies of a different site from a different site.

Lets go through these steps taking a sample java application.

First user login,
Server will validates the user and create all the cookies needed (CSRF and Session)
if (username.equals("admin") && password.equals("admin")){ HttpSession session = request.getSession();
String Session_Id = session.getId();
Cookie sessionCookie = new Cookie("Session_Cookie",Session_Id);
response.addCookie(sessionCookie);
String CSRF_Token = generateToken();
Cookie CSRF_Cookie = new Cookie("CSRF_Token",CSRF_Token);
response.addCookie(CSRF_Cookie);
response.sendRedirect("welcome.jsp");
}else{
request.getRequestDispatcher("index.jsp").forward(request, response);
}
   
I used hard-coded user credentials for demonstration purpose.

Next, in the web page javascript will collect all the cookies and identify the CSRF token cookie and add its value to a hidden field in the DOM

               <script src="js/jquery-2.2.4.js"></script>
<script type="text/javascript">
function getCookie(cname){
var name = cname + "=";
var decodedCookie = decodeURIComponent(document.cookie);
var ca = decodedCookie.split(';');
for(var i = 0; i <ca.length; i++) {
var c = ca[i];
while (c.charAt(0) === ' ') {
c = c.substring(1);
}
if (c.indexOf(name) === 0) {
return c.substring(name.length, c.length);
}
}
return "";
}
var csrfcookie = getCookie("CSRF_Token");
$(document).ready(function(){
window.onload = function() {
$('#token').val(csrfcookie);
}});

So next, the server receive the following form with the hidden token value.

                                 
<form method="post" action="SessionDemo">
<table border="0" cellpadding="2" cellspacing="2">
<tr>
<td>First Name</td>
<td><input type="text" name="fname" /></td>
</tr>
<tr>
<td>Last Name</td>
<td><input type="text" name="lname" /></td>
</tr>
<tr>
<td>&nbsp;</td>
<td><input type="submit" name="buttn" value="Submit" /></td>
</tr>
</table>
<input type="hidden" id="token" name="token" value="a"/>
</form>


So the server validates the both cookie value and the hidden field value and process according to the results of this validation process.

The following is the function to get a specific cookie.

                      String Cookie_Value = null;

String Cookie_Name = null;
String token = null;
public static Cookie getCookie(HttpServletRequest request, String name) {
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (Cookie cookie : cookies) {
if (cookie.getName().equals(name)) {
return cookie;
}
}
}
return null;
}

Validation is done by using the following code segment,

try{
Cookie tokenCookie = getCookie(request,"CSRF_Token");
Cookie_Name = tokenCookie.getName();
Cookie_Value = tokenCookie.getValue();
System.out.println(Cookie_Name+" : "+Cookie_Value);
token = request.getParameter("token");
System.out.println("Token in DOM : "+token);
if(token != null){
if(token.equals(Cookie_Value)){
out.println("Form submitted successfully");
}else{
out.println("Error occur while validating the CSRF token");
}
}else{
out.println("CSRF token absent or value is null/empty");
}
}finally{
out.close();
}

So, after all of these steps, server will get the final decision.

If you want to view the source code of this application, its available in my GitHub account.

Comments

Popular posts from this blog

Google Hacking Guide

Sanitizing application text fields