Today I upgraded from Spring Security 3.1.4 with the separate java config dependency, to the new 3.2.0 release which includes java config. CSRF is on by default and I know I can disable it in my overridden configure method with "http.csrf().disable()". But suppose I don't want to disable it, but I need the CSRF token on my login page where no JSP tag libs or Spring tag libs are being used.
My login page is purely HTML that I use in a Backbone app that I've generated using Yeoman. How would I go about including the CSRF token that's contained in the HttpSession in either the form or as a header so that I don't get the "Expected CSRF token not found. Has your session expired?" exception?
You can obtain the CSRF using the request attribute named _csrf as outlined in the reference. To add the CSRF to an HTML page, you will need to use JavaScript to obtain the token that needs to be included in the requests.
As of Spring Security 4.0, CSRF protection is enabled by default with XML configuration.
CSRF (Cross Site Request Forgery) is a technique in which an attacker attempts to trick you into performing an action using an existing session of a different website. Spring Security when combined with Thymeleaf templates, automatically inserts a token into all web forms as a hidden field.
You can obtain the CSRF using the request attribute named _csrf as outlined in the reference. To add the CSRF to an HTML page, you will need to use JavaScript to obtain the token that needs to be included in the requests.
It is safer to return the token as a header than in the body as JSON since JSON in the body could be obtained by external domains. For example your JavaScript could request a URL processed by the following:
CsrfToken token = (CsrfToken) request.getAttribute("_csrf"); // Spring Security will allow the Token to be included in this header name response.setHeader("X-CSRF-HEADER", token.getHeaderName()); // Spring Security will allow the token to be included in this parameter name response.setHeader("X-CSRF-PARAM", token.getParameterName()); // this is the value of the token to be included as either a header or an HTTP parameter response.setHeader("X-CSRF-TOKEN", token.getToken());
Your JavaScript would then obtain the header name or the parameter name and the token from the response header and add it to the login request.
Although @rob-winch is right I would suggest to take token from session. If Spring-Security generates new token in SessionManagementFilter
using CsrfAuthenticationStrategy
it will set it to Session but not on Request. So it is possible you will end up with wrong csrf token.
public static final String DEFAULT_CSRF_TOKEN_ATTR_NAME = HttpSessionCsrfTokenRepository.class.getName().concat(".CSRF_TOKEN"); CsrfToken sessionToken = (CsrfToken) request.getSession().getAttribute(DEFAULT_CSRF_TOKEN_ATTR_NAME);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With