I read a lot about Spring Securitys CSRF protection, but i still struggle a little bit. Now the documentation is great as usual, but it's completely based on the idea that you render html code on the server and are able to add a hidden field to every form. Now since i use AngularJS and JavaScript to call the backend this is not really an option.
So what is the best way to actually get the Token to the client in this case (Rest Backend / AngularJS frontend)? AngularJS seems to have built in support for CSRF in $resource and expects a Cookie called "XSRF-TOKEN" to retrieve the Token and send it as http header "X-XSRF-TOKEN" in further requests. So every request will contain the http header, as well as the cookie. Now on server side i could read the header and compare it to the Token i stored in the session.
The problem i have with this, it that it seems a bit complicated. Since the login itself has to be protected it would require creating a temporary session, just for the CSRF token. Is this really necessary?
Maybe this is just a stupid question, but why can't i just create a random-token on client side and set it as HTTP header and cookie on client side. This would be similar to "OWASP double submit cookie", but generate the Token on client-side. That way the server would not require to have a session before login, since he could just compare the 2 submitted tokens. Now while the attacker could send the HTTP header, he would per same-origin-policy have no way of reading or setting the cookie and could not get a match as long as the number is practically unguessable.
Now instinctly generating a secure token on client side seems dangerous to me and i guess i coul avoid it.. but WHY? I feel like i am missed something, surely there is a good reason why SpringSecurity stores the token in the session, right?
Please enlighten me :)
I ended up using spring-security-csrf-token-interceptor-extended, which reads the CSRF-Token from the http-header "X-CSRF-TOKEN" (name is configurable) and sends it as http-header on further requests.
Now the only thing i had to to was getting Spring-Security to send the Token as HTTP Header (since i don't render html code on serverside and therefor can't add it as a hidden field).
<security:http ....
<security:custom-filter ref="csrfTokenResponseHeaderBindingFilter" after="CSRF_FILTER"/>
....
</security:http>
The filter basically runs after the normal CSRF_FILTER and reads the "_csrf" request-attribute (which is put there by CSRF_FILTER) and sets it as header "X-CSRF-TOKEN"
public class CsrfTokenResponseHeaderBindingFilter extends OncePerRequestFilter {
protected static final String REQUEST_ATTRIBUTE_NAME = "_csrf";
protected static final String RESPONSE_TOKEN_NAME = "X-CSRF-TOKEN";
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, javax.servlet.FilterChain filterChain) throws ServletException, IOException {
CsrfToken token = (CsrfToken) request.getAttribute(REQUEST_ATTRIBUTE_NAME);
if (token != null) {
response.setHeader(RESPONSE_TOKEN_NAME, token.getToken());
}
filterChain.doFilter(request, response);
}
}