当前位置: 首页 > 知识库问答 >
问题:

Spring Boot安全性-启用CSRF时无法上载文件(多部分)

陶锋
2023-03-14

我想从angularJS客户端上传文件。我已经启用了CSRF保护,它可以正常工作,但当我尝试上载文件时,会出现403错误:

在请求参数“_CSRF”或标头“X-XSRF-Token”上发现无效的CSRF令牌“null”。

但是令牌在请求头中,并且是正确的!当我禁用CSRF保护时,我可以毫无问题地上传文件。

除此之外,CSRF保护工作正常。

以下是我当前的配置:

安全Configuration.java

@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    private SecurityUserDetailsService securityUserDetailsService;
    @Autowired
    private AuthFailureHandler authFailureHandler;
    @Autowired
    private AjaxAuthSuccessHandler ajaxAuthSuccessHandler;

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

        http
                .exceptionHandling()
                .authenticationEntryPoint(authFailureHandler)
                .and()
                .authorizeRequests()
                .antMatchers(
                        "/",
                        "/index.html",
                        "/styles/**",
                        "/bower_components/**",
                        "/scripts/**"
                ).permitAll().anyRequest()
                .authenticated()
                .and().formLogin().loginPage("/login").permitAll()
                .and().logout().logoutUrl("/logout").logoutSuccessHandler(ajaxAuthSuccessHandler).permitAll()
                .and().httpBasic()
                .and().addFilterAfter(new CsrfHeaderFilter(), CsrfFilter.class)
                .csrf().csrfTokenRepository(csrfTokenRepository());
    }

    private CsrfTokenRepository csrfTokenRepository() {
        HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
        repository.setHeaderName("X-XSRF-TOKEN");
        return repository;
    }


    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
                .userDetailsService(securityUserDetailsService)
                .passwordEncoder(new BCryptPasswordEncoder());
    }

}

CsrfHeaderFilter.java

public class CsrfHeaderFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {

        CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
        if (csrf != null) {
            Cookie cookie = WebUtils.getCookie(request, "XSRF-TOKEN");
            String token = csrf.getToken();
            if (cookie == null || token != null && !token.equals(cookie.getValue())) {
                cookie = new Cookie("XSRF-TOKEN", token);
                cookie.setPath("/");
                response.addCookie(cookie);
            }
        }
        filterChain.doFilter(request, response);
    }
}

最后,我添加了一个SecurityWebApplicationInitializer,正如这里所指出的。

SecurityWebApplicationInitializer。JAVA

public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer {
    @Override
    protected void beforeSpringSecurityFilterChain(ServletContext servletContext) {
        insertFilters(servletContext, new MultipartFilter());
    }

}

我做错了什么?

更新:我添加了这个配置,但我仍然得到了403。

@Configuration
public class MultipartUploadConfig {

    @Bean(name = "filterMultipartResolver")
    public MultipartResolver multipartResolver() {
        return new CommonsMultipartResolver();
    }
}

共有3个答案

魏兴邦
2023-03-14

您可以执行以下操作来为每个Ajax调用提供令牌:

var token = $("meta[name='_csrf']").attr("content");
var header = $("meta[name='_csrf_header']").attr("content");
$(document).ajaxSend(function(e, xhr, options) {
    xhr.setRequestHeader(header, token);
});

还有一个StackOverflow帖子谈到了这一点,我就是在那里找到的,但我已经有一段时间没有看到它了。

赏成益
2023-03-14

如果使用Ajax,请在url中放置令牌参数,然后在表单action中执行操作:

url: "/uploadFile?${_csrf.parameterName}=${_csrf.token}"

它变成这样:

function uploadFile() {
      $.ajax({
        url: "/uploadFile?${_csrf.parameterName}=${_csrf.token}",
        type: "POST",
        data: new FormData($("#upload-file-form")[0]),
        enctype: 'multipart/form-data',
        processData: false,
        contentType: false,
        cache: false,
        success: function () {
          // Handle upload success
          $("#upload-file-message").text("File succesfully uploaded");
        },
        error: function () {
          // Handle upload error
          $("#upload-file-message").text(
              "File not uploaded (perhaps it's too much big)");
        }
      });
    }
锺离旻
2023-03-14

如果您同意将CSRF令牌作为url参数发送,那么这是一个快速解决方案。在html模板中。

<form .... th:action="@{/upload(${_csrf.parameterName}=${_csrf.token})}">
...
</form>
 类似资料:
  • 禁用csrf后,我可以上传文件,但我需要启用它。问题仅发生在表单enctype是multipart/form-data时,即带有403的“无效CSRF令牌”。 通常,当我将enctype设置为多部分/表单数据时,即使对于没有文件上载的表单,也会出现相同的错误。 使用此依赖项: 尝试在表单中包含隐藏的csrf输入,并尝试将其附加到url,但出现相同错误 对于csrf注入,有这样的控制器建议 在安全方

  • 我试图创建一个页面,用户可以张贴图像及其细节。现在,当我测试来自postman的spring boot服务时,我能够成功地在服务中获取文件。当我试图从angular5中做同样的事情时,多部分文件在服务中没有被识别,并且总是得到空数组。 我的角服务代码如下 } 我已经尝试添加标头,如multipart/form-data,并将其设置为un定义。无论哪种方式,我都收到了错误。在发布到这里之前,我已经广

  • 我正在使用Spring Boot(1.5.7)和ng2文件上传(1.2.1)将文件上传到服务器。 所以我遇到了下一个问题,当文件上传开始并中断时(例如关闭浏览器选项卡),Spring Boot会记录下一个错误(两次): 当我将@ExceptionHandler添加到@ControllerAdvice时: 和应用程序的下一个属性。属性: 现在,当文件上载中断时,@ExceptionHandler会按

  • 我得到以下错误- 当我调用AWS API从JS启动多部分上传时,正如其他用户在其他讨论中建议的那样,我也在我的策略中添加了PutObjectACL。然而,我仍然不断地得到这个错误- 以下是我的政策- 我使用下面ajax调用,也通过授权在头- 授权是- AWS4-HMAC-SHA256凭证=访问密钥ID/20160331/us-east-1/服务/AWS4_请求,签名头=授权;主办x-amz-dat

  • 尝试使用将多个图像文件上载到 而且 我正试图在那里上传两个图像文件。发布数据/图像会产生两次此错误: 无法在S3上创建多部分上载:{“消息”:“访问被拒绝”,“堆栈”:“AccessDenied:访问被拒绝\n在Request.Extractorr(/Vagrant/Node_Modules/AWS-SDK/Lib/Services/S3.js:538:35)\n在Request.CallList

  • Im使用Spring Boot,并希望使用控制器接收多部分文件上传。当发送文件时,我一直得到错误415不支持的内容类型响应,并且控制器从未到达 我尝试在HTML/JSP页面和使用RESTTemplate的独立客户端应用程序中使用Form:Action发送。所有尝试的结果都是一样的 从multipart文档看来,边界参数必须添加到multipart上载,但这似乎与控制器接收不匹配 我的控制器方法设置