我用,
在其中,我使用内置的安全令牌来防御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'或标头’X-CSRF-TOKEN’上发现无效的CSRF令牌’null’。
'_csrf'或
类型状态报告
消息在请求参数'_csrf'或标头’X-CSRF-TOKEN’上发现无效的CSRF令牌’null’。
'_csrf'
描述禁止访问指定的资源。
该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相关。)
的实现UserDetailsService中可以找到这个矿的早期问题,如果需要的话。
UserDetailsService
MultipartFilter在Spring Security之前放置也无济于事。
MultipartFilter
该web.xml文件如下所示。
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>
在这种情况下,因为它是一个多部分请求,其中CSRF令牌是不可用的弹簧安全除非MultipartFilter连同MultipartResolver被适当配置,使多部分请求可以由弹簧进行处理。
MultipartResolver
MulipartResolver在applicationContext.xml文件中必须注册如下
MulipartResolver
applicationContext.xml
<bean id="filterMultipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <property name="maxUploadSize" value="-1" /> </bean>
该属性值-1的maxUploadSize看跌期权对上传文件的大小没有限制。该值可以根据要求而变化。如果有多个文件,则文件大小是所有上载文件的大小。
-1
maxUploadSize
也,
<servlet-name>/*</servlet-name>
的<filter-mapping>的MultipartFilter需要被改变,以
<filter-mapping>
<url-pattern>/*</url-pattern>