一、简述
除了核心的 OGNL 注入和文件上传漏洞,Struts 2 框架的常见漏洞还集中在重定向 / 转发注入、类型转换漏洞、拦截器配置缺陷、依赖组件漏洞、XML 配置注入等方面,这些漏洞虽未必都是 RCE 级高危,但易被组合利用,也是攻防重点。
二、重定向 / 转发注入漏洞(Open Redirect)
核心原理
Struts 2 的redirect/redirectAction结果类型,或手动拼接response.sendRedirect()时,若直接使用未过滤的用户输入作为跳转 URL,会导致开放重定向攻击。
典型场景
-
Action 中接收
redirectUrl参数,直接用于重定向:java// 危险代码 public String execute() { String redirectUrl = ServletActionContext.getRequest().getParameter("redirectUrl"); return "redirect:" + redirectUrl; // 用户可传入恶意URL } -
struts.xml中配置redirectAction时使用动态参数:XML<!-- 危险配置 --> <result name="redirect" type="redirect">${redirectUrl}</result>
危害
- 钓鱼攻击:诱导用户跳转到仿冒网站(如
https://your-site.com/redirect?redirectUrl=http://fake-bank.com); - 配合 CSRF:绕过浏览器同源策略,窃取用户 Cookie/Token。
修复方案
-
白名单校验 (最安全):仅允许跳转到预定义的合法域名 / 路径:
java// 安全示例 private static final Set<String> ALLOWED_REDIRECT_DOMAINS = Set.of("your-site.com", "api.your-site.com"); public String execute() { String redirectUrl = getRedirectUrl(); URL url = new URL(redirectUrl); if (!ALLOWED_REDIRECT_DOMAINS.contains(url.getHost())) { return "error"; // 非法跳转,返回错误页 } return "redirect:" + redirectUrl; } -
禁用动态拼接 :在
struts.xml中使用固定 URL,避免 OGNL 表达式:XML<!-- 安全配置 --> <result name="redirect" type="redirect">/home.action</result>
三、类型转换漏洞
核心原理
Struts 2 的OGNL 类型转换器(Type Converter)在处理用户输入(如字符串转对象、数组)时,若输入格式异常,可能触发:
- 拒绝服务(DoS):构造特殊输入导致 OOM / 死循环;
- 信息泄露:类型转换异常时,返回详细的栈跟踪信息(包含类路径、数据库配置);
- 绕过校验:利用类型转换规则绕过参数校验(如字符串转布尔值时,
"false"被转为true)。
典型 CVE:CVE-2020-17530
- 影响版本:2.5.0-2.5.29
- 原理:OGNL 类型转换时处理
null值不当,导致 DoS 攻击。
修复方案
-
升级至 2.5.30 + 版本;
-
自定义类型转换器,增加异常捕获和输入校验:
javapublic class SafeStringToBooleanConverter extends DefaultTypeConverter { @Override public Object convertValue(Map context, Object value, Class toType) { if (value == null) { return false; // 统一处理null值 } try { return super.convertValue(context, value, toType); } catch (Exception e) { // 屏蔽异常详情,返回默认值 return false; } } } -
关闭生产环境的异常栈跟踪:
XML<!-- struts.xml --> <constant name="struts.devMode" value="false" /> <constant name="struts.exception.logEnabled" value="true" /> <constant name="struts.exception.wrapWithActionError" value="true" />
四、拦截器配置缺陷
1. 拦截器未生效 / 绕过
原理
- Action 未继承
struts-default包,导致默认安全拦截器(如params、validation)未加载; - 自定义拦截器栈时,遗漏核心安全拦截器;
- 通过
!、*等特殊字符绕过拦截器匹配规则。
典型场景
XML
<!-- 危险配置:自定义包未继承struts-default,拦截器全部失效 -->
<package name="custom" namespace="/" abstract="true">
<interceptors>
<interceptor-stack name="myStack">
<!-- 遗漏params、validation等安全拦截器 -->
<interceptor-ref name="logger"/>
</interceptor-stack>
</interceptors>
<default-interceptor-ref name="myStack"/>
</package>
修复方案
-
所有自定义包必须
extends="struts-default"; -
自定义拦截器栈需包含
defaultStack(核心安全拦截器):XML<interceptor-stack name="mySecureStack"> <interceptor-ref name="defaultStack"/> <!-- 包含params、validation、fileUpload等 --> <interceptor-ref name="logger"/> <!-- 自定义拦截器后置 --> </interceptor-stack>
2. 权限拦截器(RolesInterceptor)绕过
原理
RolesInterceptor仅校验角色名称是否匹配,但未校验角色是否真实存在,或可通过参数篡改绕过:
- 传入
roles=*通配符; - 构造空角色参数,触发拦截器逻辑漏洞。
修复方案
-
禁用
RolesInterceptor的通配符匹配; -
结合 Spring Security/Shiro 做二次权限校验,不依赖 Struts 内置拦截器;
-
硬编码允许的角色列表,禁止动态传入: xml
<interceptor-ref name="roles"> <param name="allowedRoles">ADMIN,OPERATOR</param> <!-- 固定角色,不使用${} --> </interceptor-ref>
五、依赖组件漏洞
Struts 2 的核心功能依赖第三方组件,这些组件的漏洞会直接传导到 Struts 应用,是易被忽视的 "间接漏洞":
1. XWork 组件漏洞
XWork 是 Struts 2 的核心依赖,旧版本存在:
- OGNL 解析逻辑漏洞(如 CVE-2021-31805);
- 序列化 / 反序列化漏洞(CVE-2022-41852)。
2. Freemarker/Velocity 模板注入
Struts 2 整合 Freemarker/Velocity 时,若模板中直接使用${}渲染用户输入(而非 Struts 标签),会导致模板注入:
html
<!-- 危险的Freemarker模板 -->
<div>${param.username}</div> <!-- 直接渲染用户输入,可注入Freemarker表达式 -->
<!-- 安全写法 -->
<div><s:property value="username" escapeHtml="true"/></s:property></div>
3. Commons FileUpload 漏洞
Struts 2 默认使用commons-fileupload处理文件上传,该组件旧版本(<1.4)存在:
- 路径遍历(CVE-2018-11771);
- 内存溢出(DoS)漏洞。
修复方案
-
同步升级 Struts 依赖的所有组件:
XML<!-- pom.xml 强制升级核心依赖 --> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.5</version> <!-- 最新稳定版 --> </dependency> <dependency> <groupId>org.freemarker</groupId> <artifactId>freemarker</artifactId> <version>2.3.33</version> </dependency> -
模板渲染必须使用 Struts 标签(
s:property),并开启escapeHtml="true"。
六、XML 配置注入(Struts 配置文件漏洞)
核心原理
若 Struts 的struts.xml/struts-config.xml支持动态加载(如从数据库 / 外部文件读取配置),攻击者可注入恶意 XML 节点:
- 新增恶意 Action,执行任意代码;
- 修改拦截器配置,禁用安全拦截器;
- 注入
redirect节点,实现开放重定向。
典型场景
- 应用允许上传
struts.xml配置文件; - 通过 JNDI 加载远程恶意
struts.xml。
修复方案
-
禁止动态加载外部
struts.xml:XML<!-- struts.xml 禁用动态配置加载 --> <constant name="struts.configuration.files" value="struts-default.xml,struts.xml" /> <constant name="struts.configuration.reload" value="false" /> <!-- 生产环境禁用配置热加载 --> -
将
struts.xml放在WEB-INF目录下(禁止外部访问); -
校验配置文件的 MD5 / 签名,防止被篡改。
总结
- Struts 2 的非核心漏洞中,重定向注入、拦截器配置缺陷、依赖组件漏洞是实际攻防中最常出现的,需重点关注配置层面的加固;
- 类型转换漏洞和 XML 配置注入虽危害稍低,但易被组合利用,核心防护手段是禁用 dev 模式、升级依赖、白名单校验;
- 所有漏洞的底层防护逻辑一致:最小权限原则 (禁用不必要的功能)+ 输入白名单 (拒绝一切未校验的用户输入)+ 版本及时升级。