Pratap A.K
Pratap A.K

Reputation: 4517

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.

Upvotes: 4

Views: 13066

Answers (4)

Unmitigated
Unmitigated

Reputation: 89224

In Spring Security 6, CsrfConfigurer#ignoringRequestMatchers can be used.

For example:

@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    http.csrf(csrf -> csrf.ignoringRequestMatchers("/workflow/**"));
    return http.build();
}

Upvotes: 1

PraveenKumar Lalasangi
PraveenKumar Lalasangi

Reputation: 3543

Only one purpose of answering in this thread is to explain and use antPathMatcher whose advantages can be taken to protect many urls with ant matchers.

From Doc

.csrf().requireCsrfProtectionMatcher(RequestMatcher requireCsrfProtectionMatcher)


Specify the RequestMatcher to use for determining when CSRF should be applied. The default is to ignore GET, HEAD, TRACE, OPTIONS and process all other requests.

Note that by default GET, HEAD, TRACE, OPTIONS requests are ignored. If you want to override this defaults configure requireCsrfProtectionMatcher(implementation_of_RequestMatcher).

In implementation of RequestMatcher define all the URL's which needs to be protected. You are done

Say you want URL's /api/** to be ensured for CSRF protection.

@Autowired
RequestMatcher csrfProtectedMatchers;

@Override
protected void configure(final HttpSecurity http) throws Exception
{
    http
        .authorizeRequests()
            .antMatchers("/resources/**", "/", "/login").permitAll()
            .antMatchers("/api/**").hasAnyRole("ADMIN", "USER")
            .antMatchers("/app/user/*")
                .hasAnyRole("ADMIN", "USER")
        .and().formLogin()
        .and().csrf().requireCsrfProtectionMatcher(csrfProtectedMatchers);
}

@Bean
public RequestMatcher getCsrfProtectedMatchers()
{
    UrlPathHelper urlPathHelper = new UrlPathHelper();
    AntPathMatcher antPathMatcher = new AntPathMatcher();

    List<String> protectedUrlPatterns = Arrays.asList("/api/**", "/logout");

    return new RequestMatcher()
    {
        @Override
        public boolean matches(HttpServletRequest request)
        {
            String uri = urlPathHelper.getPathWithinApplication(request);
            for (String pattern : protectedUrlPatterns)
            {
                if (antPathMatcher.match(pattern, uri))
                {
                    return true;
                }
            }
            return false;
        }
    };
}

Logic explained
suppose URL: http://localhost:8080/csrf/api/test1
String uri = urlPathHelper.getPathWithinApplication(request);
uri => /api/test1;
antPathMatcher.match("/api/**", "/api/test1") => true

Upvotes: 1

Slava Semushin
Slava Semushin

Reputation: 15204

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/**")

Upvotes: 7

Pratap A.K
Pratap A.K

Reputation: 4517

answer for my own question... thanks to @Slava

@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());
        }
    }

Upvotes: 0

Related Questions