【问题标题】:¿How i can disable CSRF only for my api with spring security?¿我如何才能只为我的带有弹簧安全性的 api 禁用 CSRF?
【发布时间】:2017-03-12 16:42:33
【问题描述】:

我正在使用 spring 安全性创建一个带有 spring 的项目,但我只遇到了我的 api 的问题(所有控制器都与 csrf 一起正常工作)。但似乎 csrf 对我的 api 造成了问题,因为当我向我的 api 发出请求时,我得到:

{"id":41,"titulo":"vineta3","creationdate":1489421003000,"URL":"http://i2.kym-cdn.com/photos/images/facebook/000/125/918/RMUBQ.png","likes":0,"dislikes":0,"descripcion":"des3"}{"timestamp":1489421218765,"status":200,"error":"OK","exception":"java.lang.IllegalStateException","message":"Cannot create a session after the response has been committed","path":"/api/vineta/41/"}

最后的信息:

{"timestamp":1489421218765,"status":200,"error":"OK","exception":"java.lang.IllegalStateException","message":"Cannot create a session after the response has been committed","path":"/api/vineta/41/"}

当我的项目没有春季安全时,不会返回。我将下一个代码用于我的安全配置。

public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

@Autowired
public UserRepositoryAuthenticationProvider authenticationProvider;

@Override
protected void configure(HttpSecurity http) throws Exception {

    // Public pages
    http.authorizeRequests().antMatchers("/").permitAll();
    http.authorizeRequests().antMatchers("/login").permitAll();
    http.authorizeRequests().antMatchers("/loginerror").permitAll();
    http.authorizeRequests().antMatchers("/registro").permitAll();
    http.authorizeRequests().antMatchers("/signup").permitAll();
    http.authorizeRequests().antMatchers(HttpMethod.GET, "/api/**").permitAll();        


    // Private pages (all other pages)
    http.authorizeRequests().antMatchers("/home").hasAnyRole("USER");
    //http.authorizeRequests().antMatchers("/crearComentario/vineta/{id}").hasAnyRole("USER");

    // Login form
    http.formLogin().loginPage("/login");
    http.formLogin().usernameParameter("username");
    http.formLogin().passwordParameter("password");
    http.formLogin().defaultSuccessUrl("/home");
    http.formLogin().failureUrl("/loginerror");

    // Logout
    http.logout().logoutUrl("/logout");
    http.logout().logoutSuccessUrl("/");

}

@Override
protected void configure(AuthenticationManagerBuilder auth)
        throws Exception {
    // Database authentication provider
    auth.authenticationProvider(authenticationProvider);
}

}

我的 csrf 的下一个:

@Configuration
public class CSRFHandlerConfiguration extends WebMvcConfigurerAdapter {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new CSRFHandlerInterceptor());
    }
}

class CSRFHandlerInterceptor extends HandlerInterceptorAdapter {

    @Override
    public void postHandle(final HttpServletRequest request,
            final HttpServletResponse response, final Object handler,
            final ModelAndView modelAndView) throws Exception {

        CsrfToken token = (CsrfToken) request.getAttribute("_csrf"); 
        modelAndView.addObject("token", token.getToken());      
    }
}

在控制台中,我可以看到以下日志: 在

org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.0.32.jar:8.0.32]
    at java.lang.Thread.run(Thread.java:745) [na:1.8.0_25]
Caused by: java.lang.IllegalStateException: Cannot create a session after the response has been committed
    at org.apache.catalina.connector.Request.doGetSession(Request.java:2928) ~[tomcat-embed-core-8.0.32.jar:8.0.32]

我没有使用 SingleTransactionsController,这可能是问题所在?

【问题讨论】:

  • 更改后我现在得到:{"timestamp":1489421060885,"status":200,"error":"OK","exception":"java.lang.IllegalStateException","message ":"在提交响应后无法创建会话","path":"/api/usuarios/"} 并且在我的控制台上我看到:ERROR 32628 --- [nio-8080-exec-3] o.a.c.c.C. [Tomcat].[localhost] : 异常处理ErrorPage[errorCode=0, location=/error] org.springframework.web.util.NestedServletException: 请求处理失败;嵌套异常是 java.lang.IllegalStateException: 响应提交后无法创建会话

标签: spring spring-boot spring-security spring-tool-suite


【解决方案1】:

我不明白你为什么要使用CSRFHandlerInterceptor,但是如果你只想为 API 禁用 CRSF,我有两个解决方案:

  1. 您可以将requireCsrfProtectionMatcher 注入到 CSRF 过滤器中,例如:

     http
         .csrf()
             .requireCsrfProtectionMatcher(newAndRequestMatcher(CsrfFilter.DEFAULT_CSRF_MATCHER, new RegexRequestMatcher("^(?!/api/)", null)));
    

    默认匹配器是方法匹配器,第二个匹配器用于not/api/请求。

  2. 你可以只为/api创建一个新的Spring Security config,并在默认的Spring Security config之前设置顺序,匹配没有CSRF的API URL:

    http.requestMatcher(new AntPathRequestMatcher("/api/**")).csrf().disable();
    

【讨论】:

    【解决方案2】:

    为 API 和 Web 启用安全性的另一种方法是将其包含在您的 SecurityConfig 类中:

    @Override
    protected void configure(HttpSecurity http) throws Exception {
                http
                .authorizeRequests()
                .antMatchers(....)
                //form login etc
                .and().csrf().ignoringAntMatchers("/api/**");
      }
    

    【讨论】:

      【解决方案3】:

      Csrf 设置在 Spring Security 中是全局的

      这会有所帮助:

      http.csrf().requireCsrfProtectionMatcher(new RequestMatcher() {
      
              private Pattern allowedMethods = Pattern.compile("^(GET|HEAD|TRACE|OPTIONS)$");
             // regex to match your api url 
              private RegexRequestMatcher apiMatcher = new RegexRequestMatcher("/v[0-9]*/.*", null);
      
              @Override
              public boolean matches(HttpServletRequest request) {
                  // No CSRF due to allowedMethod
                  if(allowedMethods.matcher(request.getMethod()).matches())
                      return false;
      
                  // No CSRF due to api call
                  if(request.getRequestURI().equals("/view/cpanel/Login.jsp");
                      return false;
      
                  // CSRF for everything else that is not an API call or an allowedMethod
                  return true;
              }
          });
      

      【讨论】:

        【解决方案4】:

        如果您的 API 使用会话 cookie 以外的其他东西进行身份验证,例如基本身份验证或 API 令牌,那么只允许这些请求通过的简单方法是:

        .csrf()
            .requireCsrfProtectionMatcher(new AndRequestMatcher(
                CsrfFilter.DEFAULT_CSRF_MATCHER,
                new RequestHeaderRequestMatcher(HttpHeaders.COOKIE)));
        

        【讨论】:

          猜你喜欢
          • 2014-02-20
          • 2013-01-25
          • 1970-01-01
          • 2016-06-19
          • 2015-08-02
          • 2015-12-20
          • 2019-02-03
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多