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

2024-01-26

I use,

  • Spring 框架 4.0.0 发布(GA)
  • Spring Security 3.2.0 发布(正式版)
  • 支柱 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>

生成的HTML代码如下。

<form id="dataForm"
      name="dataForm"
      action="/TestStruts/admin_side/Category.action"
      method="POST"
      enctype="multipart/form-data">

    <input type="hidden"
           name="_csrf"
           value="3748c228-85c6-4c3f-accf-b17d1efba1c5" 
           id="dataForm__csrf">
</form>

这工作正常,除非请求是多部分的在这种情况下,请求以状态代码 403 结束。

HTTP 状态 403- 在请求中发现无效的 CSRF 令牌“null” 参数“_csrf”或标头“X-CSRF-TOKEN”。

type状况报告

message在请求参数中发现无效的 CSRF 令牌“null” “_csrf”或标头“X-CSRF-TOKEN”。

描述对指定资源的访问已被禁止。

The spring-security.xml文件如下。

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
             xmlns:beans="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
           http://www.springframework.org/schema/security
           http://www.springframework.org/schema/security/spring-security-3.2.xsd">

    <http pattern="/Login.jsp*" security="none"></http>

    <http auto-config='true' use-expressions="true" disable-url-rewriting="true" authentication-manager-ref="authenticationManager">
        <session-management session-fixation-protection="newSession">
            <concurrency-control max-sessions="1" error-if-maximum-exceeded="true" />
        </session-management>

        <csrf/>

        <headers>
            <xss-protection />
            <frame-options />
            <!--<cache-control />-->
            <!--<hsts />-->
            <content-type-options /> <!--content sniffing-->
        </headers>

        <intercept-url pattern="/admin_side/**" access="hasRole('ROLE_ADMIN')" requires-channel="any"/>
        <form-login login-page="/admin_login/Login.action" authentication-success-handler-ref="loginSuccessHandler" authentication-failure-handler-ref="authenticationFailureHandler"/>
        <logout logout-success-url="/admin_login/Login.action" invalidate-session="true" delete-cookies="JSESSIONID"/>
    </http>

    <beans:bean id="encoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/>

    <beans:bean id="daoAuthenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
        <beans:property name="userDetailsService" ref="userDetailsService"/>
        <beans:property name="passwordEncoder" ref="encoder" />
    </beans:bean>

    <beans:bean id="authenticationManager" class="org.springframework.security.authentication.ProviderManager">
        <beans:property name="providers">
            <beans:list>
                <beans:ref bean="daoAuthenticationProvider" />
            </beans:list>
        </beans:property>
    </beans:bean>

    <authentication-manager>
        <authentication-provider user-service-ref="userDetailsService">
        </authentication-provider>
    </authentication-manager>

    <beans:bean id="loginSuccessHandler" class="loginsuccesshandler.LoginSuccessHandler"/>
    <beans:bean id="authenticationFailureHandler" class="loginsuccesshandler.AuthenticationFailureHandler" />

    <global-method-security secured-annotations="enabled" proxy-target-class="false" authentication-manager-ref="authenticationManager">
        <protect-pointcut expression="execution(* admin.dao.*.*(..))" access="ROLE_ADMIN"/>
    </global-method-security>
</beans:beans>

那么,当请求是多部分的时,在哪里寻找这个令牌呢? (这应该与 Struts 完全无关。)

The implementation of UserDetailsService can be found in this https://stackoverflow.com/q/20919913/1391249 earlier question of mine, if needed.


Placing MultipartFilter在Spring Security之前 http://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#csrf-multipartfilter也没有帮助。

The web.xml文件如下所示。

<?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>

仅当令牌作为查询字符串参数附加时才有效,如下所示,但不鼓励这样做。

<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>

如果您使用@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:

@EnableWebMvc
@Configuration
@Import({ SecurityConfig.class })
public class AppConfig {

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

SecurityConfig.java 扩展了 WebSecurityConfigurerAdapter 并且是 SpringSecurity 的配置

multipart/form-data 过滤器(MultipartFilter)需要在启用 CSRF 的 SecurityConfig 之前注册。你可以这样做:

安全初始化器.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, "/*");

}
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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

随机推荐

  • C# TagLib 设置 Mp3 专辑封面

    我有一个 mp3 文件 我想向其中添加专辑封面 艺术作品已保存到临时文件夹中 我已检查过它 它就在那里并且是 jpeg 这是我给出的代码 public void AddMp3Tags TagLib File file TagLib File
  • JavaScript;如何设置三位数字后的点?

    我有以下 JavaScript 代码 var calculation select name somevalue1 option selected data calc select name somevalue1 option select
  • 在 EF Core 中设置默认日期时间值

    所以问题是我无法设置模型以便迁移显示DateTimeKind Utc代替DateTimeKind Unspecified我正在这样做 contactsConfiguration Property c gt c DateAdded Value
  • 在C++中连接两个大文件

    我有两个 std ofstream 文本文件 每个文件有一百多兆 我想将它们连接起来 使用 fstream 存储数据来创建单个文件通常会因大小太大而导致内存不足错误 有没有比 O n 更快的方法来合并它们 文件 1 160MB 0 1 3
  • GraphQL - 将枚举值作为参数直接传递给突变?

    给出以下 GraphQL 类型定义 const typeDefs enum Action update delete type Mutation doSomething action Action 此查询有效 const query mut
  • C 中的异常处理 - setjmp() 返回 0 有什么用?

    我有一些有关 setjmp longjmp 使用的问题 setjmp jmp buf stackVariables 返回 0 有什么用 它是默认值 我们无法影响 setjmp stackVariables 的唯一意义就是将 stackVar
  • 如何从 Java 调用具体的 Scala 特征方法?

    我有一个 Java Scala 混合 Maven 项目 我需要重用 Saddle 方法make具体定义为称为特征的一部分Index 方法已定义here https github com saddle saddle blob master s
  • 在多屏幕环境中最大化窗口而不隐藏/阻止任务栏

    这是一篇写给所有曾经问过自己 如何在多屏幕设置中最大化窗口而不阻塞任务栏 的人的文章 问题似乎是一个窗口最大化框 and 最小化框设置为 false 并且在多屏幕环境中以编程方式最大化涵盖entire屏幕 不仅是屏幕 工作区 为了仅最大化工
  • 行为和事件触发器有什么区别?

    在 Xamarin Forms 中你有行为 https developer xamarin com guides cross platform xamarin forms working with behaviors 对某些事件执行某些操作
  • 使用 try-with-resources 语句声明 Stream 与不使用 try-with-resources 语句有什么区别?

    在Java 8中 Stream 即AutoCloseable 不能被重用 一旦被消耗或使用 流将被关闭 那么用 try with resources 语句声明的实用程序是什么 try with resources 语句的示例 public
  • 选择量角器中的第一个可见元素

    我正在编写量角器测试并且喜欢它 尽管有时似乎会陷入一些看起来应该很简单的事情 例如 我想循环浏览其中一个页面上包含 提名 文本的所有按钮 页面上有几十个 但只有 1 或 2 个可见 所以我想点击第一个 这是我当前使用的代码 var nomi
  • 在 Rails 模型中动态生成范围

    我想动态生成范围 假设我有以下模型 class Product lt ActiveRecord Base POSSIBLE SIZES small medium large scope small where size small scop
  • 通过 https 运行 Angular Cli Ng Serve 2018

    有没有办法可以通过 https 运行我的 Angular localhost 我尝试了一些不同的教程 但没有任何效果我尝试过 通过 https 为您的 Angular cli 应用程序提供服务 https freerangeeggs net
  • NodeJS Mongo - Mongoose - 动态集合名称

    所以 我想创建一个基于客户端的分区模式 其中我将集合名称设置为 function 我的伪代码是这样的 var mongoose require mongoose Schema mongoose Schema var ConvForUserS
  • 刷新令牌的正确方法

    有一个功能getUser in RequestManager class那叫我的VC func getUser onCompletion escaping result User error String gt Void Alamofire
  • Elmah.MVC 在生产环境中不记录错误

    我使用以下命令将 Elmah MVC 安装到我的 MVC 项目中Elmah MVC Nuget 包 http nuget org packages Elmah MVC 它在开发环境中工作正常 但是当我将网站上传到托管服务器 IIS7 时 它
  • 如何旋转仪表图表中的刻度盘?情节地使用Python

    我最近开始使用plotlypython 中的仪表图包 完成教程和模板后here https plot ly python gauge charts 我想知道是否有办法在给定角度值的情况下旋转 表盘 或 针 有人建议我使用 css 转换做到这
  • 如何将图例放置在带边框的字段集中? [复制]

    这个问题在这里已经有答案了 根据网络上的几个参考文献 不可能定位图例 所以建议用span包裹起来 legend span Foo span legend 然后我们可以将跨度定位在字段集中 但是当我想在字段集顶部添加边框时 图例有一个间隙 幸
  • 使用 openGL 的粒子过滤器扫描线

    我正在用 C 实现用于 3D 立方体跟踪的粒子过滤器 在为粒子分配权重时 我遇到了一个重大问题 因为权重基于样本点和像素之间的距离误差 在本例中 如下所述 目前 我可以从笔记本电脑上的摄像头获取视频流 将其显示在屏幕上并在其上绘制粒子 我还
  • 当要发送的请求是多部分请求时,Spring CSRF 令牌不起作用

    I use Spring 框架 4 0 0 发布 GA Spring Security 3 2 0 发布 正式版 支柱 2 3 16 其中 我使用内置的安全令牌来防范 CSRF 攻击 Struts 表单如下所示