CSRF (Cross-site request forgery) protection in spring MVC
Asked Answered
A

2

9

I'm little confuse in this CSRF (Cross-site request forgery) protection in spring. No I have my jsp and my controller and a web service. What I want to do is validate the token at the web service level and if token is a match, run the web service (In my case do a db insert)

JSP file

    <form:input type="text" class="form-control" path="mName" />

    <input type="hidden" name="${_csrf.parameterName}"
        value="${_csrf.token}" />

    <div class="form-action">
        <input type="submit" value="Save" class="btn btn-primary" />
    </div>
</form:form>

I've inserted the hidden tag also. Now what should I do to validate this token. I'm little lost there.

At the controller class I get the values from the form to an object and call the web ervise to save data

@RequestMapping(method = RequestMethod.POST)
  public String processForm(@ModelAttribute(value = "userForm") @Valid UserForm userForm, BindingResult result, ModelMap model) {      

   //call the web service
  }
Attalanta answered 21/3, 2014 at 9:41 Comment(6)
Based upon the fact this is tagged with spring-security and you are using _csrf attribute is it safe to assume you are using Spring Security? If so, you do not need to validate the CSRF manually, Spring Security will do this for you. If this is not sufficient for you, can you expand on why that isn't working? Last, if you really need to validate it yourself, you can use an instance of HttpSessionCsrfTokenRepository to obtain the expected token.Oak
@RobWinch Yes I'm using spring security and I'm concern because "Acunetix WVS" tool found that HTML page doesn't have CSRF protectionAttalanta
Can you elaborate on how it isn't working? Can you provide your Security configuration? What does the rendered HTML look like? What do the logs look like? Did you follow the instructions here docs.spring.io/spring-security/site/docs/3.2.x/reference/…Oak
Never mind on my questions...I see you have accepted an answer. Glad to see you got it workingOak
@RobWinch I follwed that link. The problem was I was working suing spring security 3.1.x version. There I have to do this manually. Which means I have to genarate a unique token and sent it with each request and validateAttalanta
@Attalanta Can u pls share how did u solved server side validation ? I am using spring security 3.2.5.RELEASEAlkalosis
A
6

Apparently I was using spring security 3.1.4.RELEASE. here you have do this manually. Then I changed it to 3.2.2.RELEASE and then I just had to use

<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />

Refer this link to see whats new in spring security 3.2

http://docs.spring.io/spring-security/site/docs/3.2.0.RELEASE/reference/htmlsingle/#new

Be careful, when you change from 3.1.4.RELEASE to 3.2.2.RELEASE, there are lot of confusing re factorings to do. Specially in web.xml and spring-security.xml files

Attalanta answered 24/3, 2014 at 9:33 Comment(3)
Will i have to write any code on controller side for validating token on server side or spring will handle automatically? How about AJAX? I am using spring security 3.2.5.RELEASEAlkalosis
@Manish no you dont need to do any saver side validation manually. spring will handle itAttalanta
@Manish check my answer for this question to find out how to do use CSRF tokens for javascript #22631847Attalanta
S
9

OWASP Enterprise Security API has a very good option offering solid protection against CSRF. CSRF is actually pretty easy to solve. OWASP ESAPI provides the specifications to implement CSRF protection as below.

1. Generate new CSRF token and add it to user once on login and store user in http session.

This is done in the default ESAPI implementation, and it is stored as a member variable of the User object that gets stored in the session.

/this code is in the DefaultUser implementation of ESAPI
/** This user's CSRF token. */
private String csrfToken = resetCSRFToken();
...
public String resetCSRFToken() {
    csrfToken = ESAPI.randomizer().getRandomString(8, DefaultEncoder.CHAR_ALPHANUMERICS);
    return csrfToken;
}

2. On any forms or urls that should be protected, add the token as a parameter / hidden field.

The addCSRFToken method below should be called for any url that is going to be rendered that needs CSRF protection. Alternatively if you are creating a form, or have another technique of rendering URLs (like c:url), then be sure to add a parameter or hidden field with the name "ctoken" and the value of DefaultHTTPUtilities.getCSRFToken().

//from HTTPUtilitiles interface
final static String CSRF_TOKEN_NAME = "ctoken";
//this code is from the DefaultHTTPUtilities implementation in ESAPI
public String addCSRFToken(String href) {
    User user = ESAPI.authenticator().getCurrentUser();
    if (user.isAnonymous()) {
        return href;
    }
    // if there are already parameters append with &, otherwise append with ?
    String token = CSRF_TOKEN_NAME + "=" + user.getCSRFToken();
    return href.indexOf( '?') != -1 ? href + "&" + token : href + "?" + token;
}
...
public String getCSRFToken() {
    User user = ESAPI.authenticator().getCurrentUser();
    if (user == null) return null;
    return user.getCSRFToken();
}

3. On the server side for those protected actions, check that the submitted token matches the token from the user object in the session.

Ensure that you call this method from your servlet or spring action or jsf controller, or whatever server side mechanism you're using to handle requests. This should be called on any request that you need to validate for CSRF protection. Notice that when the tokens do not match, it's considered a possible forged request.

//this code is from the DefaultHTTPUtilities implementation in ESAPI
public void verifyCSRFToken(HttpServletRequest request) throws IntrusionException {
    User user = ESAPI.authenticator().getCurrentUser();
    // check if user authenticated with this request - no CSRF protection required
    if( request.getAttribute(user.getCSRFToken()) != null ) {
        return;
    }
    String token = request.getParameter(CSRF_TOKEN_NAME);
    if ( !user.getCSRFToken().equals( token ) ) {
        throw new IntrusionException("Authentication failed", "Possibly forged HTTP request without proper CSRF token detected");
    }
}

4. On logout and session timeout, the user object is removed from the session and the session destroyed.

In this step, logout is called. When that happens, note that the session is invalidated and the current user object is reset to be an anonymous user, thereby removing the reference to the current user and accordingly the csrf token.

//this code is in the DefaultUser implementation of ESAPI
public void logout() {
    ESAPI.httpUtilities().killCookie( ESAPI.currentRequest(), ESAPI.currentResponse(), HTTPUtilities.REMEMBER_TOKEN_COOKIE_NAME );
    HttpSession session = ESAPI.currentRequest().getSession(false);
    if (session != null) {
        removeSession(session);
        session.invalidate();
    }
    ESAPI.httpUtilities().killCookie(ESAPI.currentRequest(), ESAPI.currentResponse(), "JSESSIONID");
    loggedIn = false;
    logger.info(Logger.SECURITY_SUCCESS, "Logout successful" );
    ESAPI.authenticator().setCurrentUser(User.ANONYMOUS);
}

Source: http://www.jtmelton.com/2010/05/16/the-owasp-top-ten-and-esapi-part-6-cross-site-request-forgery-csrf/

Hope this helps you out.

Shishir

Speroni answered 21/3, 2014 at 14:19 Comment(0)
A
6

Apparently I was using spring security 3.1.4.RELEASE. here you have do this manually. Then I changed it to 3.2.2.RELEASE and then I just had to use

<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />

Refer this link to see whats new in spring security 3.2

http://docs.spring.io/spring-security/site/docs/3.2.0.RELEASE/reference/htmlsingle/#new

Be careful, when you change from 3.1.4.RELEASE to 3.2.2.RELEASE, there are lot of confusing re factorings to do. Specially in web.xml and spring-security.xml files

Attalanta answered 24/3, 2014 at 9:33 Comment(3)
Will i have to write any code on controller side for validating token on server side or spring will handle automatically? How about AJAX? I am using spring security 3.2.5.RELEASEAlkalosis
@Manish no you dont need to do any saver side validation manually. spring will handle itAttalanta
@Manish check my answer for this question to find out how to do use CSRF tokens for javascript #22631847Attalanta

© 2022 - 2024 — McMap. All rights reserved.