javaspring-bootspring-securitycsrfrest-client

how to ignore spring security CSRF for specific URL's in spring boot project


how can I ignore CSRF security for specific URL which is like "/workflow/**". Except for this URL, I need both authorization and CSRF security for all the URL's and methods.

@Configuration
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
protected static class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    private RESTAuthenticationEntryPoint authenticationEntryPoint;

    @Autowired
    private RESTAuthenticationFailureHandler authenticationFailureHandler;

    @Autowired
    private RESTAuthenticationSuccessHandler authenticationSuccessHandler;

    @Autowired
    private PranaUserDetailsService userDetailsService;

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http.csrf().requireCsrfProtectionMatcher(new AllExceptUrlStartedWith("/workflow"))          
        .and().authorizeRequests()
        .antMatchers("/rest/**", "/tasklist").authenticated()
        .and().logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
        .logoutSuccessUrl("/index.html")        
        .and().exceptionHandling().authenticationEntryPoint(authenticationEntryPoint)
        .and().formLogin().successHandler(authenticationSuccessHandler)
        .and().formLogin().failureHandler(authenticationFailureHandler)         
        .and().csrf().csrfTokenRepository(csrfTokenRepository()).and().addFilterAfter(new CsrfHeaderFilter(), CsrfFilter.class);
    }

    private static class AllExceptUrlStartedWith implements RequestMatcher {

        private static final String[] ALLOWED_METHODS =
                new String[] {"GET"};

        private final String[] allowedUrls;

        public AllExceptUrlStartedWith(String... allowedUrls) {
            this.allowedUrls = allowedUrls;
        }

        @Override
        public boolean matches(HttpServletRequest request) {
            String method = request.getMethod();
            for(String allowedMethod : ALLOWED_METHODS) {
                if (allowedMethod.equals(method)) {
                    return false;
                }
            }

            String uri = request.getRequestURI();
            for (String allowedUrl : allowedUrls) {
                if (uri.startsWith(allowedUrl)) {
                    return false;
                }
            }
            return true;
        }

    }

    private CsrfTokenRepository csrfTokenRepository() {
        HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
        repository.setHeaderName("X-XSRF-TOKEN");
        return repository;
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/styles/**").antMatchers("/scripts/**");
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(new BCryptPasswordEncoder());
    }
}

how can I ignore CSRF security for specific URL which is like "/workflow/**". Except for this URL, I need both authorization and CSRF security for all the URL's and methods.


Solution

  • In my project I'm using the following code:

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
            ...
            .csrf()
                // Allow unsecured requests to H2 console
                .requireCsrfProtectionMatcher(new AllExceptUrlsStartedWith("/console"))
            ...
    }
    
    private static class AllExceptUrlsStartedWith implements RequestMatcher {
    
            private static final String[] ALLOWED_METHODS =
                new String[] {"GET", "HEAD", "TRACE", "OPTIONS"};
    
            private final String[] allowedUrls;
    
            public AllExceptUrlsStartedWith(String... allowedUrls) {
                this.allowedUrls = allowedUrls;
            }
    
            @Override
            public boolean matches(HttpServletRequest request) {
                // replicate default behavior (see CsrfFilter.DefaultRequiresCsrfMatcher class)
                String method = request.getMethod();
                for (String allowedMethod : ALLOWED_METHODS) {
                    if (allowedMethod.equals(method)) {
                        return false;
                    }
                }
    
                // apply our own exceptions
                String uri = request.getRequestURI();
                for (String allowedUrl : allowedUrls) {
                    if (uri.startsWith(allowedUrl)) {
                        return false;
                    }
                }
    
                return true;
            }
    
        }
    

    In this example I've disabled CSRF protection for /console.


    Update: since Spring Security 4.0 you can simplify it to a single line:

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