33

I am using Spring-Security 3.2.0.RC2 with Java config. I set up a simple HttpSecurity config that asks for basic auth on /v1/**. GET requests work but POST requests fail with:

HTTP Status 403 - Invalid CSRF Token 'null' was found on the request parameter '_csrf' or header 'X-CSRF-TOKEN'.

My security config looks like this:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

@Resource
private MyUserDetailsService userDetailsService;

@Autowired
//public void configureGlobal(AuthenticationManagerBuilder auth)
public void configure(AuthenticationManagerBuilder auth)
        throws Exception {
    StandardPasswordEncoder encoder = new StandardPasswordEncoder(); 
    auth.userDetailsService(userDetailsService).passwordEncoder(encoder);
}

@Configuration
@Order(1)
public static class RestSecurityConfig
        extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .antMatcher("/v1/**").authorizeRequests()
                .antMatchers("/v1/**").authenticated()
            .and().httpBasic();
    }
}

}

Any help on this greatly appreciated.

shawnim
  • 580
  • 1
  • 6
  • 11
  • 1
    If you dan't want to disable csrf (since it is there for a reason) you could add a hidden field with the csrf-value and add the value like starmandeluxe suggests in the accepted post. This worked fine for me, without disabling csrf – Xtroce Jan 29 '15 at 16:14
  • @Xtroce is right, though in my case I had to add `X-CSRF-TOKEN` to the ajax post *headers*. (Adding `_csrf` to the ajax post *parameters* didn't work.) – inanutshellus Mar 12 '15 at 03:08
  • Adding to @Xtroce comment, if you use thymeleaf for templating, you can add
    and the template engine will automatically provide a hidden input field named "_csrf" populated with the correct value.
    – Daniel Huang Mar 12 '15 at 20:46

2 Answers2

54

CSRF protection is enabled by default with Java configuration. To disable it:

@Configuration
public class RestSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .csrf().disable()
            ...;
    }
}
holmis83
  • 15,922
  • 5
  • 82
  • 83
  • 5
    So, the obvious question is, if he isn't disabling it, what was his problem with the null value? I am actually having the same issue and I'm not disabling CSRF protection as far as I know. – starmandeluxe May 15 '14 at 05:34
  • 2
    @starmandeluxe When CSRF protection is enabled, Spring Security expects a CSRF token from the client when using POST. If the client doesn't send such a token, it will be null, which means missing. – holmis83 May 15 '14 at 08:36
  • 1
    Oh, but I am sending in my AJAX call: beforeSend: function(xhr) { xhr.setRequestHeader('X-CSRF-Token', $("meta[name='_csrf']").attr('content')); – starmandeluxe May 15 '14 at 08:37
  • @starmandeluxe Hard to say what's wrong with so little information. Different question really; the OP was asking regarding a REST service, your concern is about AJAX. – holmis83 May 15 '14 at 12:23
  • Fair enough, but my problem isn't really with AJAX. It's that the "${_csrf.token}" that should be resolved into an actual token by Spring Security isn't getting converted into a token. I made a separate question here: http://stackoverflow.com/questions/23669424/cant-create-csrf-token-with-spring-security – starmandeluxe May 16 '14 at 00:52
6

You can also disable the CSRF check only on some requests or methods, using a configuration like the following for the http object:

http
  .csrf().requireCsrfProtectionMatcher(new RequestMatcher() {

    private Pattern allowedMethods = 
      Pattern.compile("^(GET|HEAD|TRACE|OPTIONS)$");

    private RegexRequestMatcher apiMatcher = 
      new RegexRequestMatcher("/v[0-9]*/.*", null);

    @Override
    public boolean matches(HttpServletRequest request) {
        // CSRF disabled on allowedMethod
        if(allowedMethods.matcher(request.getMethod()).matches())
            return false;

        // CSRF disabled on api calls
        if(apiMatcher.matches(request))
            return false;

        // CSRF enables for other requests
        return true;
    }
});

You can see more here:

http://blog.netgloo.com/2014/09/28/spring-boot-enable-the-csrf-check-selectively-only-for-some-requests/

Andrea
  • 15,900
  • 18
  • 65
  • 84