How to Prevent Cross-Site Request Forgery (CSRF) in SpringMVC
Posted by Serge Truth on Tue, Dec 27, 2011 @ 08:00 AM
Applies to
Summary
Perform CSRF prevention using SpringMVC within an application.
Objectives
CSRF prevention is a key security control for an application that protects the application and its users from CSRF attacks. This article will describe how to use the built-in mechanisms provided by SpringMVC to perform CSRF prevention.
Solution Example
There is a standard model for CSRF prevention using SpringMVC that involves 3 basic steps
- Build a base controller with CSRF generation and validation methods.
public class RootController {
...
protected void init(ControllerContext ctx) {
...
initializeCsfrToken(ctx);
}
private void initializeCsfrToken(ControllerContext ctx) {
String csrfToken = ctx.getSessionAttribute(ControllerContext.CSRF_TOKEN, "");
if(Utils.isEmpty(csrfToken)) {
ctx.setSessionAttribute(ctx, ControllerContext.CSRF_TOKEN, generateCsrfToken(ctx));
}
}
private String generateCsrfToken(ControllerContext ctx) {
... generate random string
}
protected boolean isValidCsrfToken(ControllerContext ctx) {
String csrfParamToken = ctx.getParameter(ControllerContext.CSRF_TOKEN);
String csrfSessionToken = ctx.getSessionAttribute(ControllerContext.CSRF_TOKEN, "");
if(!Utils.isEmpty(csrfParamToken) && !Utils.isEmpty(csrfSessionToken) && csrfParamToken.equals(csrfSessionToken)) {
return true;
} else {
//Log this as this can be a security threat
Log.warn("Invalid security Token. Supplied token: " + csrfParamToken + ". Session token: " + csrfSessionToken + ". IP: " + ctx.request.getRemoteAddr());
return false;
}
}
- Include CSRF token in form submitted via JSP.
<input type="hidden" name="ctoken" id="ctoken" value="${sessionScope.ctoken}"/>
- In Controller handling request, validate CSRF token. In the action class/method that handles the saving of your form (ex. SaveBookController), you need to perform the token validation.
...
ControllerContext ctx = new ControllerContext(request, response);
init(ctx);
if (!isValidCsrfToken(ctx)) {
result.addError(new ObjectError("employee", getMessage("error.invalidCsrfToken")));
return getModelAndView(ctx, "employee/list");
}
...
Using these 3 simple steps you can effectively have a session specific per user token used to validate that a request was submitted by a user intentionally.
Note: There have been effective attacks against various CSRF prevention techniques including this token-based approach when an application has XSS vulnerabilities. Removing XSS is therefore viewed as a prerequisite activity for a complete CSRF prevention mechanism.
In conclusion, CSRF prevention can function as a strong security control if used properly and applied thoroughly throughout the application. The SpringMVC framework provides a simple series of steps for accomplishing this task.
More Information