如何忽略特定 URL(如“/workflow/**”)的 CSRF 安全性。 除了这个 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(如“/workflow/**”)的 CSRF 安全性。 除了这个 URL 之外,我还需要所有 URL 和方法的授权和 CSRF 安全性。
在我的项目中,我使用以下代码:
@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 保护。
更新:从 Spring Security 4.0 开始,您可以将其简化为一行:
csrf()
.ignoringAntMatchers("/nocsrf","/ignore/startswith/**")
在这个帖子中回答的唯一目的是解释和使用
antPathMatcher
,它的优点可以利用蚂蚁匹配器来保护许多网址。
来自医生
.csrf().requireCsrfProtectionMatcher(RequestMatcher requireCsrfProtectionMatcher)
指定用于确定何时应应用 CSRF 的 RequestMatcher。默认是忽略 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);
/api/test1
;antPathMatcher.match("/api/**", "/api/test1")
=> true
回答我自己的问题...感谢@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());
}
}
CsrfConfigurer#ignoringRequestMatchers
。
例如:
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.csrf(csrf -> csrf.ignoringRequestMatchers("/workflow/**"));
return http.build();
}