Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
当要发送的请求是多部分请求时,Spring CSRF令牌不起作用_Spring_Struts2_Spring Security_Csrf_Csrf Protection - Fatal编程技术网

当要发送的请求是多部分请求时,Spring CSRF令牌不起作用

当要发送的请求是多部分请求时,Spring CSRF令牌不起作用,spring,struts2,spring-security,csrf,csrf-protection,Spring,Struts2,Spring Security,Csrf,Csrf Protection,我用 SpringFramework 4.0.0发行版(GA) Spring Security 3.2.0版本(GA) Struts 2.3.16 其中,我使用内置的安全令牌来防范CSRF攻击 Struts表单如下所示 <s:form namespace="/admin_side" action="Category" enctype="multipart/form-data" method="POST" validate=

我用

  • SpringFramework 4.0.0发行版(GA)
  • Spring Security 3.2.0版本(GA)
  • Struts 2.3.16
其中,我使用内置的安全令牌来防范CSRF攻击

Struts表单如下所示

<s:form namespace="/admin_side"
        action="Category"
        enctype="multipart/form-data"
        method="POST"
        validate="true"
        id="dataForm"
        name="dataForm">

    <s:hidden name="%{#attr._csrf.parameterName}"
              value="%{#attr._csrf.token}"/>
</s:form>
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0"
         xmlns="http://java.sun.com/xml/ns/javaee" 
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
         http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            /WEB-INF/applicationContext.xml
            /WEB-INF/spring-security.xml
        </param-value>
    </context-param>

    <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>
        <servlet-name>/*</servlet-name>
    </filter-mapping>

    <filter-mapping>
        <filter-name>springSecurityFilterChain</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <filter>
        <filter-name>AdminLoginNocacheFilter</filter-name>
        <filter-class>filter.AdminLoginNocacheFilter</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>AdminLoginNocacheFilter</filter-name>
        <url-pattern>/admin_login/*</url-pattern>
    </filter-mapping>

    <filter>
        <filter-name>NoCacheFilter</filter-name>
        <filter-class>filter.NoCacheFilter</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>NoCacheFilter</filter-name>
        <url-pattern>/admin_side/*</url-pattern>
    </filter-mapping>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <listener>
        <description>Description</description>
        <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
    </listener>

    <listener>
        <listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
    </listener>

    <filter>
        <filter-name>struts2</filter-name>
        <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
        <init-param>
            <param-name>struts.devMode</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>

    <filter-mapping>
        <filter-name>struts2</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <session-config>
        <session-timeout>
            30
        </session-timeout>
    </session-config>
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
</web-app>
那么,当请求是多部分的时候,在哪里寻找这个令牌呢?(这根本不应该与支柱相关。)

如果需要,
UserDetailsService
的实现可以在我前面的问题中找到


也没有帮助

web.xml
文件如下所示

<s:form namespace="/admin_side"
        action="Category"
        enctype="multipart/form-data"
        method="POST"
        validate="true"
        id="dataForm"
        name="dataForm">

    <s:hidden name="%{#attr._csrf.parameterName}"
              value="%{#attr._csrf.token}"/>
</s:form>
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0"
         xmlns="http://java.sun.com/xml/ns/javaee" 
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
         http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            /WEB-INF/applicationContext.xml
            /WEB-INF/spring-security.xml
        </param-value>
    </context-param>

    <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>
        <servlet-name>/*</servlet-name>
    </filter-mapping>

    <filter-mapping>
        <filter-name>springSecurityFilterChain</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <filter>
        <filter-name>AdminLoginNocacheFilter</filter-name>
        <filter-class>filter.AdminLoginNocacheFilter</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>AdminLoginNocacheFilter</filter-name>
        <url-pattern>/admin_login/*</url-pattern>
    </filter-mapping>

    <filter>
        <filter-name>NoCacheFilter</filter-name>
        <filter-class>filter.NoCacheFilter</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>NoCacheFilter</filter-name>
        <url-pattern>/admin_side/*</url-pattern>
    </filter-mapping>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <listener>
        <description>Description</description>
        <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
    </listener>

    <listener>
        <listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
    </listener>

    <filter>
        <filter-name>struts2</filter-name>
        <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
        <init-param>
            <param-name>struts.devMode</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>

    <filter-mapping>
        <filter-name>struts2</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <session-config>
        <session-timeout>
            30
        </session-timeout>
    </session-config>
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
</web-app>

上下文配置位置
/WEB-INF/applicationContext.xml
/WEB-INF/spring-security.xml
多部件滤波器
org.springframework.web.multipart.support.MultipartFilter
springSecurityFilterChain
org.springframework.web.filter.DelegatingFilterProxy
多部件滤波器
/*
springSecurityFilterChain
/*
AdminLoginNocacheFilter
filter.AdminLoginLocacheFilter
AdminLoginNocacheFilter
/管理员登录/*
NoCacheFilter
过滤器
NoCacheFilter
/行政方/*
org.springframework.web.context.ContextLoaderListener
描述
org.springframework.web.context.request.RequestContextListener
org.springframework.security.web.session.HttpSessionEventPublisher
支柱2
org.apache.struts2.dispatcher.ng.filter.strutspreadexecutefilter
struts.devMode
真的
支柱2
/*
30
index.jsp
它只在令牌作为查询字符串参数追加时起作用,如下所示,但不鼓励这样做

<s:form namespace="/admin_side"
        action="Category?%{#attr._csrf.parameterName}=%{#attr._csrf.token}"
        enctype="multipart/form-data"
        method="POST"
        validate="true"
        id="dataForm"
        name="dataForm">
    ...
<s:form>

...

在这种情况下,因为它是一个多部分请求,其中CSRF令牌对Spring security不可用,除非正确配置了
MultipartFilter
以及
MultipartResolver
,以便Spring可以处理多部分请求

applicationContext.xml
文件中的
MulipartResolver
必须按如下方式注册

<bean id="filterMultipartResolver" 
      class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> 

    <property name="maxUploadSize" value="-1" />
</bean> 
需要将
多部件过滤器的
更改为

<url-pattern>/*</url-pattern>
/*
这是一个很好的例子

如果只是SpringMVC的话,这将很好地工作

但是,如果它是Spring和Struts的集成(2),那么在相关的Struts操作类中会产生另一个问题。上传文件的信息将在相关Struts操作类中
null


若要解决此特定问题,请参阅自定义的答案。

如果您使用@annotations,请参阅jsp视图,如下所示:

    <form:form id="profileForm" action="profile?id=${param.id}" method="POST" 
          modelAttribute="appUser" enctype="multipart/form-data" >
             ...
            <input type="file" name="file">
             ...
            <input type="hidden" name="${_csrf.parameterName}"
                value="${_csrf.token}" />
    </form:form>
java扩展了WebSecurity配置适配器,是SpringSecurity的配置

需要在启用CSRF的SecurityConfig之前注册多部分/表单数据筛选器(MultipartFilter)。您可以通过以下方式进行操作:

SecurityInitializer.java:

public class SecurityInitializer extends
AbstractSecurityWebApplicationInitializer {

@Override
protected void beforeSpringSecurityFilterChain(ServletContext servletContext) {
   super.beforeSpringSecurityFilterChain(servletContext);

   // CSRF for multipart form data filter:
   FilterRegistration.Dynamic springMultipartFilter;
   springMultipartFilter = servletContext.addFilter(
    "springMultipartFilter", new MultipartFilter());
   springMultipartFilter.addMappingForUrlPatterns(null, false, "/*");

}
}

您可以禁用csrf-httpSecurity.csrf().disable()


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

  • 使用香草javascript发送多部分文件,如
  • 在HTML头中的meta标记中添加_csrf标记,如Spring指南中的
  • 不使用jquery,而是直接将其添加到XHR对象

    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 Boot+Security+CSRF+多部分的情况下,多部分文件不会绑定到ModelAttribure或RequestParam(多部分文件)

下面的代码对我来说很好

1.MvcConfiguration.java

@Configuration
@EnableWebMvc
@ComponentScan
public class MvcConfiguration extends WebMvcConfigurerAdapter { 

.......
......

/*
     * Case : Spring Boot + Security + CSRF + Mulitpart 
     * In this case, since it is a multipart request in which the CSRF token is unavailable to Spring security unless MultipartFilter along with MultipartResolver 
     * is properly configured so that the multipart request can be processed by Spring.
     * 
     * And 
     * 
     * The multipart/form-data filter (MultipartFilter) needs to be registered before the SecurityConfig that enables the CSRF.
     * So that's why 
     * 1. reg.setOrder(1); //below
     * 2. security.filter-order=2 // in application.properties
     */

    @Bean
    public FilterRegistrationBean registerMultipartFilter() {
        FilterRegistrationBean reg = new FilterRegistrationBean(new MultipartFilter());
        reg.setOrder(1);
        return reg;
    }

    @Bean(name = "filterMultipartResolver")
    public CommonsMultipartResolver filterMultipartResolver() {
        CommonsMultipartResolver filterMultipartResolver = new CommonsMultipartResolver();
        filterMultipartResolver.setDefaultEncoding("utf-8");
        // resolver.setMaxUploadSize(512000);
        return filterMultipartResolver;
    }
.....
.....
}
2。application.properties

security.filter-order=2

否。禁用该令牌不是解决方案。它将大大打开CSRF孔。
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);
@Configuration
@EnableWebMvc
@ComponentScan
public class MvcConfiguration extends WebMvcConfigurerAdapter { 

.......
......

/*
     * Case : Spring Boot + Security + CSRF + Mulitpart 
     * In this case, since it is a multipart request in which the CSRF token is unavailable to Spring security unless MultipartFilter along with MultipartResolver 
     * is properly configured so that the multipart request can be processed by Spring.
     * 
     * And 
     * 
     * The multipart/form-data filter (MultipartFilter) needs to be registered before the SecurityConfig that enables the CSRF.
     * So that's why 
     * 1. reg.setOrder(1); //below
     * 2. security.filter-order=2 // in application.properties
     */

    @Bean
    public FilterRegistrationBean registerMultipartFilter() {
        FilterRegistrationBean reg = new FilterRegistrationBean(new MultipartFilter());
        reg.setOrder(1);
        return reg;
    }

    @Bean(name = "filterMultipartResolver")
    public CommonsMultipartResolver filterMultipartResolver() {
        CommonsMultipartResolver filterMultipartResolver = new CommonsMultipartResolver();
        filterMultipartResolver.setDefaultEncoding("utf-8");
        // resolver.setMaxUploadSize(512000);
        return filterMultipartResolver;
    }
.....
.....
}
security.filter-order=2