1. Struts2重定向漏洞的本质Struts2框架中的重定向漏洞本质上是一种服务端未验证用户输入导致的安全问题。当开发人员使用redirect:或redirectAction:前缀时框架会直接将用户提供的参数作为重定向目标而没有进行充分的安全校验。我曾在实际项目中遇到过这样的案例某电商平台的登录页面存在Struts2重定向漏洞攻击者构造了一个恶意链接example.com/login.action?redirecthttp://evil.com用户点击后会被诱导到钓鱼网站。由于跳转是从可信域名发起的用户往往不会产生怀疑。与普通URL重定向漏洞不同Struts2的漏洞特殊性在于通过OGNL表达式注入实现更危险的RCE远程代码执行漏洞触发点集中在特定参数前缀处理逻辑影响多个Struts2版本如S2-016、S2-057等经典漏洞2. 漏洞原理深度解析2.1 核心触发机制Struts2处理重定向请求时DefaultActionMapper类会识别以下前缀redirect:直接跳转到指定URLredirectAction:跳转到指定Action漏洞产生的关键代码路径// DefaultActionMapper.java public ActionMapping getMapping(HttpServletRequest request) { // 处理特殊前缀参数 handleSpecialParameters(request, mapping); } void handleSpecialParameters() { if (param.startsWith(redirect:)) { ServletRedirectResult result new ServletRedirectResult(); result.setLocation(param.substring(9)); // 直接使用用户输入 } }2.2 OGNL表达式注入Struts2使用OGNLObject-Graph Navigation Language表达式处理参数但未对以下场景做防护用户输入被直接拼接进OGNL表达式动态方法调用未禁用struts.enable.DynamicMethodInvocationSecurityMemberAccess权限控制不严典型攻击Payload结构redirect:%{ #_memberAccess.allowStaticMethodAccesstrue, java.lang.RuntimegetRuntime().exec(calc) }2.3 与通用URL重定向漏洞的对比特性通用URL重定向Struts2重定向漏洞触发条件任意未校验的URL参数特定前缀参数redirect:最大危害钓鱼攻击RCE钓鱼修复难度简单输入校验需框架级修复典型漏洞编号-S2-016, S2-0573. 漏洞检测实战指南3.1 自动化扫描方案推荐使用以下工具进行初步检测OWASP ZAP配置自定义脚本识别redirect:参数Burp Suite通过Scanner模块检测重定向响应Struts2漏洞扫描器如Struts2-Scan# 使用curl快速检测示例 curl -v http://target/login.action?redirecthttp://test.com # 观察响应头是否包含Location: http://test.com3.2 手工验证技巧分步骤验证方法参数发现在登录/注销等可能跳转的页面寻找参数常见参数名redirect、returnUrl、jump等基础测试修改参数值为外部域名GET /login.action?redirecthttp://evil.com HTTP/1.1OGNL测试尝试执行简单表达式GET /login.action?redirect%25%7B11%7D结果确认检查响应中的Location头或页面跳转行为3.3 Struts2专项检测针对不同版本的特殊检测方法S2-016检测/login.action?redirect:%24%7B%23context%5B%27xwork.MethodAccessor.denyMethodExecution%27%5D%3Dfalse%2C%23f%3D%23_memberAccess.getClass().getDeclaredField(%27allowStaticMethodAccess%27)%2C%23f.setAccessible(true)%2C%23f.set(%23_memberAccess%2Ctrue)%2Cjava.lang.RuntimegetRuntime().exec(%27calc%27)%7DS2-057检测!-- 构造恶意namespace -- action name${(111111)} class... result/result.jsp/result /action4. 漏洞修复方案4.1 紧急缓解措施若无法立即升级可采用以下临时方案web.xml配置过滤器filter filter-nameRedirectFilter/filter-name filter-classcom.example.RedirectFilter/filter-class /filter filter-mapping filter-nameRedirectFilter/filter-name url-pattern/*/url-pattern /filter-mappingstruts.xml安全配置constant namestruts.enable.DynamicMethodInvocation valuefalse/ constant namestruts.mapper.alwaysSelectFullNamespace valuetrue/4.2 永久修复方案版本升级建议Struts 2.3.x 系列升级到 2.3.37Struts 2.5.x 系列升级到 2.5.30升级步骤示例备份现有配置和代码修改pom.xmldependency groupIdorg.apache.struts/groupId artifactIdstruts2-core/artifactId version2.5.30/version /dependency测试所有业务功能4.3 安全编码规范白名单校验对重定向URL实施严格校验public boolean isValidRedirect(String url) { return url.matches(^https?://(www\\.)?example\\.com[/\\w-]*); }签名验证对动态URL添加HMAC签名String salt SECRET_KEY; String sign HmacUtils.hmacSha256Hex(salt, url); return url sign sign;使用索引代替URL// 配置安全跳转映射 MapInteger, String redirectMap ImmutableMap.of( 1, /home.action, 2, /dashboard.action );5. 防御体系构建5.1 分层防御策略网络层WAF规则拦截包含redirect:、OGNL表达式的请求Nginx反向代理过滤异常参数应用层统一重定向处理组件参数消毒Sanitizationpublic String sanitize(String input) { return input.replaceAll([${}()], ); }监控层日志记录所有重定向操作告警异常跳转行为如非业务域名5.2 安全开发实践禁用危险功能constant namestruts.mapper.action.prefix.enabled valuefalse/ constant namestruts.mapper.action.postfix.enabled valuefalse/安全代码示例// 安全的Struts2 Action配置 public class SafeAction extends ActionSupport { private String redirectUrl; public String execute() { if (!SecurityUtil.isSafeUrl(redirectUrl)) { return ERROR; } return SUCCESS; } }自动化安全测试// Geb测试脚本示例 def 测试重定向漏洞() { when: 提交恶意跳转参数 go login.action?redirecthttp://evil.com then: 不应出现外部跳转 !driver.currentUrl.contains(evil.com) }6. 经典漏洞案例分析6.1 S2-016漏洞详解影响版本2.0.0 - 2.3.15触发点redirect:/redirectAction:参数技术根源DefaultActionMapper未过滤OGNL表达式利用过程攻击者构造恶意URL/login.action?redirect:%25%7B%23context%5B%27xwork.MethodAccessor.denyMethodExecution%27%5D%3Dfalse%2C%23f%3D%23_memberAccess.getClass().getDeclaredField(%27allowStaticMethodAccess%27)%2C%23f.setAccessible(true)%2C%23f.set(%23_memberAccess%2Ctrue)%2C%40java.lang.Runtime%40getRuntime().exec(%27calc%27)%7D服务器解析时执行OGNL表达式实现任意命令执行6.2 S2-057漏洞详解影响版本2.3 - 2.3.34, 2.5 - 2.5.16触发场景namespace未正确配置且使用url标签技术特点双重评估OGNL表达式修复方案对比// 修复前 namespace TextParseUtil.translateVariables(namespace); // 修复后 namespace TextParseUtil.translateVariables( namespace, new OgnlValueStack(), new ParsedValueEvaluator() { public Object evaluate(String parsedValue) { return parsedValue; } } );7. 常见问题解答Q如何判断系统是否存在Struts2重定向漏洞A可通过三步验证查找使用redirect:参数的页面尝试修改参数值为外部域名测试OGNL表达式执行如%{11}Q升级Struts2版本后出现兼容性问题怎么办A建议先在测试环境验证使用mvn dependency:tree检查依赖冲突逐步替换过期的API调用QWAF能否完全防护此类漏洞A不能完全依赖WAF应该WAF作为第一道防线代码层面实现输入校验框架层面及时升级补丁8. 实战经验分享在一次安全评估中我发现某系统虽然升级了Struts2版本但通过以下方式仍存在风险遗留的旧版jar文件如struts2-core-2.3.14.jar配置文件中未禁用动态方法调用自定义拦截器未正确处理参数最终我们采取的解决方案使用Maven Enforcer插件确保版本一致plugin groupIdorg.apache.maven.plugins/groupId artifactIdmaven-enforcer-plugin/artifactId version3.0.0/version executions execution idenforce-versions/id goals goalenforce/goal /goals configuration rules requireProperty propertystruts2.version/property message必须使用安全版本/message version[2.5.30,)/version /requireProperty /rules /configuration /execution /executions /plugin建立自动化安全扫描流程对开发团队进行Struts2安全培训