5

I am trying to prevent my web application from CSRF(Cross site request forgery) I followed this link Link for CSRF

This is what I have tried. To implement this mechanism in Java I choose to use two filters, one to create the salt for each request, and another to validate it. Since the users request and subsequent POST or GETs that should be validated do not necessarily get executed in order, I decided to use a time based cache to store a list of valid salt strings.

The first filter, used to generate a new salt for a request and store it in the cache can be coded as follows:

public class LoadSalt implements Filter{


    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {

        // Assume its HTTP  
        HttpServletRequest httpReq = (HttpServletRequest)request;
        // Check the user session for the salt cache, if none is present we create one
        @SuppressWarnings("unchecked")
        Cache<String, Boolean> csrfPreventionSaltCache = (Cache<String, Boolean>)
                httpReq.getSession().getAttribute("csrfPreventionSaltCache");

        System.out.println("Checking cahce befor creating it from Request :csrfPreventionSaltCache: "+csrfPreventionSaltCache);

        if(csrfPreventionSaltCache == null)
        {
            System.out.println("csrfPreventionSaltCache is null have to create new one");
            String csrfPreventionfromrequest = (String) httpReq.getSession().getAttribute("csrfPreventionSaltCache");
            System.out.println("csrfPreventionfromrequest :"+csrfPreventionfromrequest);

            // creating a new cache 
            csrfPreventionSaltCache = CacheBuilder.newBuilder().maximumSize(5000)
                    .expireAfterAccess(20, TimeUnit.MINUTES).build();

            // Setting to gttpReq
            httpReq.getSession().setAttribute("csrfPreventionSaltCache", csrfPreventionSaltCache);

            System.out.println("After setting the csrfPreventionSaltCache to HttpReq");
            System.out.println("--------csrfPreventionSaltCache------ :"+httpReq.getSession().getAttribute("csrfPreventionSaltCache"));
        }



        // Generate the salt and store it in the users cache
        String salt = RandomStringUtils.random(20, 0, 0, true, true, null, new SecureRandom());
        System.out.println("Salt: "+salt);
        csrfPreventionSaltCache.put(salt, Boolean.TRUE);
        // Add the salt to the current request so it can be used
        // by the page rendered in this request
        httpReq.setAttribute("csrfPreventionSalt", salt);

        System.out.println("Before going to validate salt checking for salt in request");
        System.out.println(" httpReq.getAttribute(csrfPreventionSalt) ----:"+httpReq.getAttribute("csrfPreventionSalt"));
       // System.out.println(" httpReq.getSession().getAttribute(csrfPreventionSalt) :----"+httpReq.getSession().getAttribute("csrfPreventionSalt"));


        chain.doFilter(request, response);
    }
    public void init(FilterConfig arg0) throws ServletException {

    }

    public void destroy() {

    }
}

Mapping in web.xml

        <filter>
            <filter-name>loadSalt</filter-name>
            <filter-class>com.globalss.dnb.monitor.security.LoadSalt</filter-class>
        </filter>

        <filter-mapping>
             <filter-name>loadSalt</filter-name>
             <url-pattern>/*</url-pattern>
        </filter-mapping>

to validate the salt before executing secure transactions I have written another filter:

public class ValidateSalt implements Filter {

    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {

        // Assume its HTTP
        HttpServletRequest httpReq = (HttpServletRequest) request;

        //String salt = (String) httpReq.getSession().getAttribute("csrfPreventionSalt");
        String salt =(String) httpReq.getAttribute("csrfPreventionSalt");
        System.out.println("I am in ValidateSalt : salt: "+salt);

     // Validate that the salt is in the cache
        @SuppressWarnings("unchecked")
        Cache<String, Boolean> csrfPreventionSaltCache = (Cache<String, Boolean>)
            httpReq.getSession().getAttribute("csrfPreventionSaltCache");


        if(csrfPreventionSaltCache !=null && salt !=null && csrfPreventionSaltCache.getIfPresent(salt)!=null)
        {
            // If the salt is in the cache, we move on
            chain.doFilter(request, response);
        }
        else
        {
            // Otherwise we throw an exception aborting the request flow
            throw new ServletException("Potential CSRF detected!! Inform a scary sysadmin ASAP.");
        }

    }

    public void init(FilterConfig arg0) throws ServletException {

    }
    public void destroy() {

    }

}

Mapping for the second Filetr in web.xml

<filter>
            <filter-name>validateSalt</filter-name>
             <filter-class>com.globalss.dnb.monitor.security.ValidateSalt</filter-class>
        </filter>

        <filter-mapping>
            <filter-name>validateSalt</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>

After configuring both servlets all your secured requests wasfailing :). To fix it you I had to add, to each link and form post that ends in a secure URL, the csrfPreventionSalt parameter containing the value of the request parameter with the same name. For example, in an HTML form within a JSP page:

<form action="/transferMoneyServlet" method="get">
    <input type="hidden" name="csrfPreventionSalt" value="<c:out value='${csrfPreventionSalt}'/>"/>
    ...
</form>

After doing all this I try to attempt CSRF, This what I did

<html>
<body>
<form action="http://localhost:8080/mywebapp/dispatcherServlet/addUserController/addUser" method="POST" enctype="text/plain">
<input type="hidden" name="&#123;&quot;userName&quot;&#58;&quot;CSRUser&quot;&#44;&quot;password&quot;&#58;&quot;CSRFUser123&quot;&#44;&quot;roles&quot;&#58;&quot;true&quot;&#44;&quot;status&quot;&#58;&quot;true&quot;&#125;" value="" />
<input type="submit" value="Submit request" />
</form>
</body>
</html>

When I hit the submit request button , I got a success response, and CSRUser was added in my database.

am I missing something, how do I prevent CSRF attack?

Varun
  • 4,342
  • 19
  • 84
  • 119

2 Answers2

1

You can use Spring Security for users authentication and authorization. There is Cross Site Request Forgery (CSRF) support by default starting from Spring 3.2.0 version.

You can also easily exclude the URLs you do not want to protect by using RequestMatcher:

public class CsrfSecurityRequestMatcher implements RequestMatcher {
private Pattern allowedMethods = Pattern.compile("^(GET|HEAD|TRACE|OPTIONS)$");
private RegexRequestMatcher unprotectedMatcher = new RegexRequestMatcher("/unprotected", null);

@Override
public boolean matches(HttpServletRequest request) {
    if(allowedMethods.matcher(request.getMethod()).matches()){
        return false;
    }

    return !unprotectedMatcher.matches(request);
}
}

Source

Seo Bro
  • 111
  • 3
  • I am using servlet 2.5 and spring 3, does spring 3.0 provide the support for CSRF – Varun Jun 09 '16 at 13:55
  • 1
    No, Spring Security provides CSRF support starting from 3.2.0 version. https://spring.io/blog/2013/08/21/spring-security-3-2-0-rc1-highlights-csrf-protection/ – Seo Bro Jun 09 '16 at 13:58
0

I had the very same questions some days ago and I've found the very same article.

Actually, while I was copying and pasting it I was thinking about how secure it was ...

So, my first idea was to really get in a quest to understand what CSRF attacks were: OWASP - Cross Site Request Forgery.

After understand it, first thing I did was to hack my own app with both HTTP GET and POST and I was really surprise about how easy it was: Here some more explanation about CSRF and how to do it).

Finally, I realize "there is more in CSRF attacks than meets the eye" and definetly, this article does not guarantee any security at all since there's no explanation about token injection and so, you can't assure the attacker is not in possession of a valid token. In this case, filtering token is useless.

In this point, I recomend some more reading in OWASP CSRF Prevention Cheat Sheet to get more deep into it.

Last but not least, in my case, I've decided to use de OWASP CSRF Guard library which is very configurable/flexible and open source. So, in the end, if you decide not to go with it, at least you will have a better idea of how to implement it your own by following some of its architecture.

[update]

Well, unfortunally I couldn't go with CSRF Guard either, because of the following drawbacks:

  1. It is based on synchronous ajax request which is in the process of being removed from the web platform: https://xhr.spec.whatwg.org/

  2. I couldn't make it work with dynamic form generation because it is not possible to access the token to add a hidden field in the dynamic form. Which is by design I think, but I could not change my app to adapt to this reality;

  3. I couldn't make it work with multipart forms;

Fortunately, I've crossed a very good answer here which directs me to do my own implementation using "Set-Cookie" strategy.

I hope it helps.

Community
  • 1
  • 1
Reginaldo Santos
  • 840
  • 11
  • 24