Spring-boot: Can i disable CSRF check for some controllers?

Created on 21 Dec 2013  路  20Comments  路  Source: spring-projects/spring-boot

Hello,

currently i have a small app that has 2 controllers, one for a rest like api and one for basic web stuff.
for the web stuff i use spring security for login, here i want CSRF check enabled, but for the rest api i dont need/want CSRF protection.

is there a way to disable the CSRF protection only for the Api controller or the /api/* request pattern but have it enabled for everything else?

all i found yet is to disable CSRF at all.

Thanks in Advance

PS: I'm using spring-boot 0.5.0.BUILD-SNAPSHOT

Most helpful comment

FYI...Spring Security 4.0 added ignoringAntMatchers:

csrf()
    .ignoringAntMatchers("/nocsrf","/ignore/startswith/**")

All 20 comments

The security.enable_csrf configuration setting only applies to the resources which are protected by SecurityAutoConfiguration (/** by default, but I assume you have your own configuration for your own resources). You should be able to configure CSRF protection per filter chain using your own WebSecurityConfigurerAdapter. Maybe if you can share your code we can look at the problem and make more specific recommendations?

Thank you for your fast reply :)

where can i change the /** or at least add some excludes to it?

this is my current WebSecurityConfig.java

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // Dis  able CSRF
        // TODO find a way to allow CSRF for everything but API
        http.csrf().disable();

        // System stuff
        http.authorizeRequests()//
                .antMatchers("/favicon.ico").permitAll();

        // Pages
        http.authorizeRequests()//
                .antMatchers("/v1/**").permitAll()//
                .antMatchers("/v2/**").permitAll()//
                .antMatchers("/v3/**").permitAll()//
                .antMatchers("/v4/**").permitAll()//
                .antMatchers("/v5/**").permitAll()//
                // disallow everything else...
                .anyRequest().authenticated();

        http.formLogin()//
                .defaultSuccessUrl("/admin/news")//
                .loginPage("/login")//
                .permitAll();

        http.logout().permitAll();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder authManagerBuilder) throws Exception {
        // cut
    }
}

If you use @EnableWebSecurity you switch off the Spring Boot settings completely, so really this is a vanilla Security question. You could probably get help on Stackoverflow.

What you will need is 2 WebSecurityConfigurerAdapters, one with your /api/** endpoints and one with lower priority (higher @Order) to protect the rest. Disable the csrf protection in one and not the other.

hmm, i really love the black magic behind spring but sometimes it is very confusing.

i don't yet understand why @EnableWebSecurity disables Spring Boot settings. i got my WebSecurityConfig from this guide http://spring.io/guides/gs/securing-web/.

i just found https://github.com/spring-projects/spring-boot/blob/master/spring-boot-samples/spring-boot-sample-secure/src/main/java/org/springframework/boot/sample/ops/ui/SampleSecureApplication.java which i think then is the Spring Boot way to configure?

there it is

    @Bean
    public ApplicationSecurity applicationSecurity() {
            return new ApplicationSecurity();
    }

    @Order(Ordered.LOWEST_PRECEDENCE - 8)
    protected static class ApplicationSecurity extends WebSecurityConfigurerAdapter {
            @Override
            protected void configure(HttpSecurity http) throws Exception {
                    http.authorizeRequests().anyRequest().fullyAuthenticated().and().formLogin()
                                    .loginPage("/login").failureUrl("/login?error").permitAll();
            }
    }

so when i remove the @EnableWebSecurity and return my WebSecurityConfig in applicationSecurity() and add another Bean with a WebSecurityConfigurerAdapter for my api how i would tell the one for api to ignore csrf? would it be enough to have the http.csrf().disable();?

Thanks! :)

okay, i tested that.

as soon as i have http.csrf().disable(); in one of the WebSecurityConfigurerAdapter beans it disables CSRF for all :(

next test is the http.csrf().requireCsrfProtectionMatcher(RequestMatcher matcher); i just found.

this snipped works for me.

    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) {
            // No CSRF due to allowedMethod
            if(allowedMethods.matcher(request.getMethod()).matches())
                return false;

            // No CSRF due to api call
            if(apiMatcher.matches(request))
                return false;

            // CSRF for everything else that is not an API call or an allowedMethod
            return true;
        }
    });

Looks like csrf settings are global in Spring Security. Oh well.

/cc @rwinch

Was there something else needed @philwebb or was this more of an FYI?

@dodgex One thing I would suggest is avoiding anonymous inner classes within the configuration because they will have references to the configuration objects. Since the anonymous inner class is used by your application there is going to continue to be a reference to the anonymous inner class. In turn this means that the Configuration will still have a reference to it and will not be able to be garbage collected. Instead consider using a static inner class or use the existing RequestMatchers which can be use to do what you want.

@rwinch Just an FYI in case you were interested. Sorry, should have put that in the /cc comment.

@philwebb Thank you for the cc ;-)

@rwinch First of all thank you for the hint regarding the inner class and the related memory leak. i didn't knew that, although it is somehow obvious.

i'll take a look on the existing matchers if there is one that does what i need, otherwise i keep my own matcher but as a static inner class.

Thank you both! :+1:

For now i'll keep my RequestMatcher (but as a static class) as i didn't found an existing Matcher that i could use for my case.

Thanks a lot for the working snippet :)

FYI...Spring Security 4.0 added ignoringAntMatchers:

csrf()
    .ignoringAntMatchers("/nocsrf","/ignore/startswith/**")

yep, and we have to use 1.3.0.M1 version of spring-boot, because 1.2.5 do not contain this method.

If you use xml for security configurations you can add -
<http security="none" pattern="/pathWhereCSRFWillBeIgnored/**"/>

what is xml equalent of
csrf()
.ignoringAntMatchers("/nocsrf","/ignore/startswith/**")

?

That鈥檚 a usage question about a different project (appended to a closed issue). Please ask questions in stack overflow.

How can we bypass GET type URL by using:
csrf()
.ignoringAntMatchers("/nocsrf","/ignore/startswith/**") in spring-security 4 or 5

@amitrathi1982 have you seen the comment jut before yours? Please ask questions on Stackoverflow.

Was this page helpful?
0 / 5 - 0 ratings