Reputation: 4517
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
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
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
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
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