Webflux multipart/form-data,启用csrf,带有和不带有文件上传功能,都将获得无效的CSRF令牌 [英] Webflux multipart/form-data, csrf enabled, with and without file upload getting Invalid CSRF Token

查看:250
本文介绍了Webflux multipart/form-data,启用csrf,带有和不带有文件上传功能,都将获得无效的CSRF令牌的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在禁用csrf的情况下,我可以上传文件,但是我需要将其启用. 仅当表单enctype为multipart/form-data,即带有403的无效CSRF令牌"时,才会出现此问题.

With csrf disabled I can upload file however I need it enabled. The problem only occurs when the form enctype is multipart/form-data, namely 'Invalid CSRF Token' with 403.

通常,即使对于没有文件上传的表单,我都将enctype设置为multipart/form-data时,也会遇到相同的错误.

Generally when I set the enctype as multipart/form-data even for a form without file upload, I get the same error.

使用此依赖项:

<dependency>
  <groupId>org.synchronoss.cloud</groupId>
  <artifactId>nio-multipart-parser</artifactId>
  <version>...</version>
</dependency>

尝试在表单中包含隐藏的csrf输入,还尝试将其附加到url上但出现相同的错误

Tried including hidden csrf input in the form and also tried appending it to the url but same error

    <form  method="post" th:action="${'/add/' + id + '/documents?' + _csrf.headerName + '=' + _csrf.token}"  enctype="multipart/form-data">
        <input type="file" name="documents" multiple="multiple">
        <input  type="hidden"
                th:name="${_csrf.headerName}"
                th:value="${_csrf.token}" />
        <input type="hidden" name="_csrf" th:value="${_csrf.token}">
        <button class="btn btn-success btn-l">Upload</button>
    </form>

对于csrf注入有这样的控制器建议

Have a controller advice like this for csrf injection

@ControllerAdvice
public class SecurityAdvice {@ModelAttribute("_csrf")Mono<CsrfToken> csrfToken(final ServerWebExchange exchange) {
    final Mono<CsrfToken> csrfToken = exchange.getAttributeOrDefault(org.springframework.security.web.server.csrf.CsrfToken.class.getName(), Mono.empty());
    return csrfToken;
}

为了安全起见,我有以下bean:

In security I have the following bean:

 @Bean
    public ServerCsrfTokenRepository csrfTokenRepository() {
        WebSessionServerCsrfTokenRepository repository =
                new WebSessionServerCsrfTokenRepository();
        repository.setHeaderName("X-CSRF-TK");

        return repository;
    }

并在SecurityWebFilterChain中像这样使用它:

and using it like this in my SecurityWebFilterChain:

.and().csrf().csrfTokenRepository(csrfTokenRepository())

更新:

为一些URL禁用csrf也足够了.找到了一些示例,但所有示例均针对基于Servlet的版本. https://sdqali .in/blog/2016/07/20/csrf-protection-with-spring-security-and-angular-js/

Disabling csrf for a few urls would be enough too. Found a few examples but all of them are for Servlet based version. https://sdqali.in/blog/2016/07/20/csrf-protection-with-spring-security-and-angular-js/

推荐答案

看看Spring Security的官方建议: https://docs.spring.io/spring-security/site/docs/current/reference/html/csrf.html#csrf-多部分

Take a look at Spring Security's official recommendation: https://docs.spring.io/spring-security/site/docs/current/reference/html/csrf.html#csrf-multipart

基本上有两种方法可以做到:(1)将MultipartFilter放在Spring Security过滤器之前,以及(2)像执行操作一样将CSRF令牌包含在form动作中.第一个选项是推荐的选项:

There are basically two ways of doing it: (1) placing MultipartFilter before Spring Security filter and (2) include the CSRF token in the form action, as you are doing. The first option is the recommended one:

第一个选项是确保指定了MultipartFilter 在Spring Security过滤器之前.指定MultipartFilter 在Spring Security过滤器之前表示没有授权 用于调用MultipartFilter,这意味着任何人都可以放置 服务器上的临时文件.但是,只有授权用户才能 能够提交由您的应用程序处理的文件.在 通常,这是推荐的方法,因为临时文件 上传对大多数服务器的影响可以忽略不计.

The first option is to ensure that the MultipartFilter is specified before the Spring Security filter. Specifying the MultipartFilter before the Spring Security filter means that there is no authorization for invoking the MultipartFilter which means anyone can place temporary files on your server. However, only authorized users will be able to submit a File that is processed by your application. In general, this is the recommended approach because the temporary file upload should have a negligble impact on most servers.

要确保在具有Java配置的Spring Security过滤器之前指定了MultipartFilter,用户可以如下所示覆盖beforeSpringSecurityFilterChain:

To ensure MultipartFilter is specified before the Spring Security filter with java configuration, users can override beforeSpringSecurityFilterChain as shown below:

public class SecurityApplicationInitializer extends AbstractSecurityWebApplicationInitializer {

    @Override
    protected void beforeSpringSecurityFilterChain(ServletContext servletContext) {
        insertFilters(servletContext, new MultipartFilter());
    }
}

要确保在具有XML配置的Spring Security过滤器之前指定MultipartFilter,用户可以确保将MultipartFilter的元素放在web.xml中的springSecurityFilterChain之前,如下所示:

To ensure MultipartFilter is specified before the Spring Security filter with XML configuration, users can ensure the element of the MultipartFilter is placed before the springSecurityFilterChain within the web.xml as shown below:

<filter>
    <filter-name>MultipartFilter</filter-name>
    <filter-class>org.springframework.web.multipart.support.MultipartFilter</filter-class>
</filter>
<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
    <filter-name>MultipartFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

请注意,如果您仍要使用表单操作,则查询参数可能会泄漏.尝试将您的"headerName"更改为"parameterName":

Note that, if you still want to use form action, query parameters can be leaked. Try to change your "headerName" to "parameterName":

<form action="./upload?${_csrf.parameterName}=${_csrf.token}" method="post" enctype="multipart/form-data">

编辑:如果您无法切换到基于Servlet的容器​​(例如Jetty或Tomcat),并且表单操作建议不起作用,则最近有一个

EDIT: In case you can't switch to a servlet-based container (such as Jetty or Tomcat) and the form action recommendation doesn't work, there's a recent Stack Overflow thread discussing this issue.

其中一位开发人员报告使用AJAX解决此问题:

One of the developers reported to workaround the issue using AJAX:

我通过以下方法解决了这个问题:

I solved this problem by:

  • sending the multi-part file using vanilla javascript, like in Mozilla's guide
  • adding the _csrf token in the HTML header, in meta tags, like in the Spring guideline for sending the CSRF token with Ajax
  • instead of using jquery, adding it directly to the XHR object

var csrfToken = $("meta[name='_csrf']").attr("content"); var csrfHeader = $("meta[name='_csrf_header']").attr("content"); XHR.setRequestHeader(csrfHeader, csrfToken); XHR.setRequestHeader('Content-Type','multipart/form-data; boundary=' + boundary); XHR.send(data);

var csrfToken = $("meta[name='_csrf']").attr("content"); var csrfHeader = $("meta[name='_csrf_header']").attr("content"); XHR.setRequestHeader(csrfHeader, csrfToken); XHR.setRequestHeader('Content-Type','multipart/form-data; boundary=' + boundary); XHR.send(data);

同一位开发人员将此问题报告给了Spring ,但没有还没有引起注意.

The same developer reported this issue to Spring, but didn't get any attention yet.

这篇关于Webflux multipart/form-data,启用csrf,带有和不带有文件上传功能,都将获得无效的CSRF令牌的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆