【问题标题】:how to ignore spring security CSRF for specific URL's in spring boot project如何在spring boot项目中忽略特定URL的spring security CSRF
【发布时间】: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 安全。

【问题讨论】:

    标签: java spring-boot spring-security csrf rest-client


    【解决方案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 并处理所有其他请求。

    请注意,默认情况下 GETHEADTRACEOPTIONS 请求被忽略。如果要覆盖此默认值,请配置 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());
              }
          }
      

      【讨论】:

        猜你喜欢
        • 2014-04-26
        • 2020-07-15
        • 2016-09-10
        • 2018-06-21
        • 2022-06-12
        • 2021-04-21
        • 2021-07-09
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多