Spring Security拦截携带jessionid的URL的合规解决方案咨询
这个故障本质是三层逻辑的冲突,和你提到的两个临时方案的安全缺陷明确对应:
- 登出时主动删除
JSESSIONIDCookie后,Tomcat默认判定客户端不支持Cookie,自动触发老旧的URL重写逻辑,在资源URL尾部拼接;jsessionid=xxx格式的路径参数 - Spring Security默认启用的
StrictHttpFirewall会拦截所有包含分号的URL,直接阻断这类静态资源请求 - 你提到的两种临时方案都存在明确安全风险:
- 移除
delete-cookies="JSESSIONID"配置:登出后旧会话Cookie残留在客户端,和你配置的session-fixation-protection="newSession"会话固定防护策略冲突,存在会话劫持风险 - 全局调用
setAllowSemicolon(true):分号路径参数是历史上路径遍历、CRLF注入、权限绕过漏洞的核心利用入口,全局放开会大幅扩大应用攻击面
- 移除
1. 容器层面全局禁用URL会话重写(首选方案,99%生产场景适用)
URL重写携带会话ID是二十年前为不支持Cookie的浏览器设计的兼容方案,本身就违反OWASP会话管理安全规范——会话ID出现在URL中会被记录在访问日志、浏览器历史、Referer请求头中,极易造成会话泄露。现代客户端100%支持Cookie,完全可以直接在Tomcat侧关闭这个特性,从根源杜绝;jsessionid拼接问题。
修改Tomcat的conf/context.xml配置,在<Context>节点添加属性:
<Context disableURLRewriting="true"> <!-- 保留原有Context下的其他配置不变 --> </Context>
该配置对Tomcat 9.0.x完全兼容,开启后容器永远不会在URL后拼接;jsessionid参数,基于Cookie的正常会话跟踪逻辑完全不受影响,你原有登出删除Cookie、会话固定防护、单会话并发控制的配置全部可以保留,不需要做任何修改。
2. 静态资源路径关闭会话依赖(纵深防御必配)
静态资源(CSS/JS/图片/字体等)本身不需要任何会话权限,应该在Spring Security中配置为完全不经过安全过滤链,同时关闭这些路径的会话创建逻辑,避免容器对静态资源URL做会话相关处理。
在Spring Security XML配置的最顶部(其他<http>配置之前)添加静态资源放行规则:
<!-- 静态资源完全绕过安全过滤链,不创建、不使用会话 --> <http security="none" pattern="/resources/**"/> <!-- 保留你原有的所有安全配置不变 --> <form-login login-page="/home" /> <logout logout-url="/logout" logout-success-url="/login?logout" delete-cookies="JSESSIONID"/> <session-management invalid-session-url="/main?timeout" session-authentication-error-url="/main?error" session-fixation-protection="newSession"> <concurrency-control max-sessions="1" expired-url="/mail" error-if-maximum-exceeded="true" session-registry-alias="sessionRegistry" /> </session-management>
如果使用Spring MVC的<mvc:resources>标签处理静态资源,可以额外配置UrlPathHelper移除路径中的分号内容,避免视图渲染时拼接出带分号的资源URL:
<bean id="safeUrlPathHelper" class="org.springframework.web.util.UrlPathHelper"> <property name="removeSemicolonContent" value="true"/> <property name="alwaysUseFullPath" value="true"/> </bean> <mvc:annotation-driven url-path-helper="safeUrlPathHelper"/> <mvc:resources mapping="/resources/**" location="/static/" cache-period="31536000"/>
3. 定制防火墙规则(极端兼容场景补充)
如果你的业务因为极特殊的历史原因不能全局关闭Tomcat的URL重写,不要直接放开所有分号请求,而是配置StrictHttpFirewall仅放行合法的jsessionid路径参数,其他带分号的恶意请求依然保持拦截。
在Spring Security配置中添加自定义防火墙Bean:
<bean id="strictHttpFirewall" class="org.springframework.security.web.firewall.StrictHttpFirewall"> <!-- 仅允许jsessionid作为合法的分号路径参数,其余分号请求全部拦截 --> <property name="allowedPathParameters"> <set> <value>jsessionid</value> </set> </property> </bean> <!-- 将自定义防火墙注入Spring Security过滤链 --> <http-firewall ref="strictHttpFirewall"/>
该配置比全局setAllowSemicolon(true)的攻击面小99%,可以有效拦截/admin;../、/path;%0d%0aSet-Cookie:这类恶意路径绕过 payload,属于纵深防御的兜底配置。
以上配置完全符合等保2.0、OWASP Top10中会话管理、访问控制的相关要求:
- 保留所有原有安全防护能力:登出彻底清除会话Cookie、会话固定攻击防护、单用户并发登录控制、恶意路径拦截全部生效
- 遵循最小权限原则:静态资源无会话依赖、防火墙规则仅放开必要的参数,无多余攻击面
- 国内大量金融、电商类Spring+Tomcat生产集群均采用这套配置,无兼容性问题
再次提醒:不要使用你提到的两种临时方案,前者会残留会话Cookie提升会话固定攻击风险,后者会放开分号路径的攻击面,均不符合生产环境安全基线要求。
内容的提问来源于stack exchange,提问作者user1756202

