2008-06-05

CSRFGuard Testing

Well I have been playing with CSRFGuard lately from the OWASP website. Its basically allows you to set up certain pages that are CSRF protected and whenever a link is selected the http request is parsed for a token that you define and checks if that token is in your session. Below is some sample code all running on Tomcat 6X. I'm not sure if I have this completely the way they intended but it works.


Example CSRFGuard.properties:

org.owasp.csrfguard.Debug=true
org.owasp.csrfguard.ResponseHandler=org.owasp.csrfguard.handlers.JavaScriptHandler
org.owasp.csrfguard.TokenName=OWASP_CSRFTOKEN
org.owasp.csrfguard.TokenLength=32
org.owasp.csrfguard.PRNG=SHA1PRNG
org.owasp.csrfguard.action.class.Log=org.owasp.csrfguard.actions.Log
org.owasp.csrfguard.action.class.Invalidate=org.owasp.csrfguard.actions.Invalidate
org.owasp.csrfguard.action.class.Redirect=org.owasp.csrfguard.actions.Redirect
org.owasp.csrfguard.action.class.Redirect.param.ErrorPage=error.jsp

You can name the org.owasp.csrfguard.TokenName can be set to what ever you want as long as you set it in your code.

Example web.xml:

My Web.xml. Here you define the location and name of the csrfguard.properties and the resources that you wish to protect with CSRFGuard. Here I am protecting the csrfServlet.



<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="
http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
  <display-name>CSRFTest</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>
<filter>
  <filter-name>CSRFGuard</filter-name>
  <filter-class>org.owasp.csrfguard.CSRFGuardFilter</filter-class>
    <init-param>
      <param-name>config</param-name>
      <param-value>WEB-INF/csrfguard.properties</param-value>
    </init-param>
</filter>

<filter-mapping>
<filter-name>CSRFGuard</filter-name>
<servlet-name>csrfServlet</servlet-name>
</filter-mapping>

<filter-mapping>
<filter-name>CSRFGuard</filter-name>
<url-pattern>*.do</url-pattern>
</filter-mapping>

  <servlet>
      <servlet-name>csrfServlet</servlet-name>
      <servlet-class>csrfServlet</servlet-class>
  </servlet>
  <servlet-mapping>
      <servlet-name>csrfServlet</servlet-name>
      <url-pattern>/csrfServlet.do</url-pattern>
  </servlet-mapping>
  </web-app>

Example Login Page:

My Login page (kinda). This page should not be inside the CSRFGuard filter defined in the web.xml. I actually don't log in but establish a session and add my OWASP_CSRFTOKEN to my session.


<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<jsp:directive.page import="org.owasp.csrfguard.util.*"/>
<jsp:directive.page import="javax.servlet.http.*"/>

<%@ page session="true" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>

<%
TokenGenerator token = new TokenGenerator();
HttpSession sess = request.getSession(true);
String csrf = token.generateCSRFToken("SHA1PRNG",32);
sess.setAttribute("OWASP_CSRFTOKEN", csrf);

%>
<a href="/CSRFTest/csrfServlet.do?OWASP_CSRFTOKEN=<%=csrf %>" > Click me to get to Protected Site </a
>

</body>
</html>

Protected Servlet:

Below is my csrfServlet.java. There is really nothing in this code except a message stating that you made it this far.

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
import org.apache.jasper.runtime.*;

public class csrfServlet extends HttpServlet {
    /**
     *
     */
    private static final long serialVersionUID = -6429166168752177032L;

    public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
    {

        response.setContentType("text/html");
        PrintWriter out = response.getWriter();
        out.println("<html>");
        out.println("<body>");
        out.println("You Made it");
        out.println("</body>");
        out.println("</html>");
    }
}

Now I have it a working CSRF filter. For this to work all my links need to be dynamically generated to include OWASP_CSRFTOKEN=blah as in my login page or Posted through hidden fields in a form.

My questions now are:
How well will this work in a clustered environment?
How to ensure that the application has been carefully coded not to give up the CSRFToken by accident. I'm working on a proof of concept for this one.

Let me know if there is anyone else out there using CSRFGuard and your experiences with it.

4 comments:

Travis said...

nice write up,

i havent set this up before so its interesting to see someone that has. good to know it appears to work. i've just now started testing for csrf so i'm pretty new in the game. i'm curious to see more posts on this topic.

ascetik said...

I think that for devs who do not want to integrate CSRFGuard (to new, not an approved technology, etc) that just making the user reenter their username and password when modifying sensitive data would be a sufficient precaution. But CSRFGuard would make the users experience more seamless.

Anonymous said...

Who knows where to download XRumer 5.0 Palladium?
Help, please. All recommend this program to effectively advertise on the Internet, this is the best program!

justaguy007 said...

CSRFGuard is an effective after the fact solution. You can use a filter to automatically inject the token into forms. If you are using an ajax framework then you need to modify it to systematically include the token.

The only worry is that the token is for the lifetime of the session so make sure it has enough entropy to defeat a browser history based brute force attack.

I have not heard of any flaws in it yet.