如何在spring boot项目中忽略特定URL的spring security CSRF
Posted
技术标签:
【中文标题】如何在spring boot项目中忽略特定URL的spring security CSRF【英文标题】:how to ignore spring security CSRF for specific URL's in spring boot project 【发布时间】:2015-12-18 08:45:29 【问题描述】:如何忽略特定 URL 的 CSRF 安全性,例如“/workflow/**”。 除了这个 URL,我需要所有 URL 和方法的授权和 CSRF 安全。
@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());
如何忽略特定 URL 的 CSRF 安全性,例如“/workflow/**”。 除了这个 URL,我需要所有 URL 和方法的授权和 CSRF 安全。
【问题讨论】:
【参考方案1】:在我的项目中,我使用以下代码:
@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;
在本例中,我为 /console
禁用了 CSRF 保护。
更新:since Spring Security 4.0 you can simplify it to a single line:
csrf()
.ignoringAntMatchers("/nocsrf","/ignore/startswith/**")
【讨论】:
嗨@Slava:它不适合我! /login 和 /workflow/** 都出现 403 禁止错误......有什么帮助吗?? 所以,请在某处发布您更新的 Spring 安全配置(例如 pastebin)。 谢谢斯拉瓦。实际上这是我的错误,由于我公司的特定依赖关系而出错。它正在工作,现在我为“/workflow”调用禁用了 CSRF,并为所有其他休息调用启用了 CSRF 再次感谢您的帮助 使用antPathMatcher.match()
将生成用于定义诸如/console/**
之类的通配符URL 的最少代码。您可以在我的回答中参考。【参考方案2】:
在此线程中回答的唯一目的是解释和使用antPathMatcher
,它的优点可以利用蚂蚁匹配器保护许多网址。
来自文档
.csrf().requireCsrfProtectionMatcher(RequestMatcher requireCsrfProtectionMatcher)
指定 RequestMatcher 用于确定何时应用 CSRF。默认是忽略 GET、HEAD、TRACE、OPTIONS 并处理所有其他请求。
请注意,默认情况下 GET
、HEAD
、TRACE
、OPTIONS
请求被忽略。如果要覆盖此默认值,请配置 requireCsrfProtectionMatcher(implementation_of_RequestMatcher)
。
在 RequestMatcher 的实现中定义所有需要保护的 URL。 你完成了
假设您希望确保 URL 的 /api/**
用于 CSRF 保护。
@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;
;
逻辑解释
假设网址:http://localhost:8080/csrf/api/test1
String uri = urlPathHelper.getPathWithinApplication(request);
uri => /api/test1
;antPathMatcher.match("/api/**", "/api/test1")
=> true
【讨论】:
【参考方案3】:回答我自己的问题...感谢@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());
【讨论】:
以上是关于如何在spring boot项目中忽略特定URL的spring security CSRF的主要内容,如果未能解决你的问题,请参考以下文章
如何将 Spring Boot @RepositoryRestResource 映射到特定的 url?
如何将Spring Boot RepositoryRestResource映射到特定的URL
在 spring-boot 中禁用特定 url 的 Keycloak 身份验证