structs2漏洞
2010年,一个名为“S2-001”的编号开始在安全圈疯传。Apache Struts2的OGNL表达式注入漏洞,让全世界无数基于Java的Web应用一夜之间变成裸奔状态。攻击者只需在URL或表单里塞进一段精心构造的字符串,服务器就会乖乖执行任意命令——拿权限、拖数据库、挂后门,一条龙服务,全程无需认证。
这个漏洞的本质,是框架把用户输入直接当作OGNL表达式解析了。Struts2的核心组件ValueStack,本该负责数据流转,却成了攻击者的跳板。你输入一串数学公式,它算给你看;你输入一段系统命令,它也照单全收。这种“输入即信任”的设计缺陷,在Java生态里埋下了长达十年的雷。
更讽刺的是,Struts2的漏洞修复史几乎就是一场打地鼠游戏。S2-001修完,S2-003来了;S2-003补上,S2-005又爆了。每次修补都像是在给漏水的船换个新补丁,可船底早就烂透了。直到2017年,S2-045和S2-046利用Content-Type和Content-Disposition头绕过防护,直接导致Equifax数据泄露——1.43亿美国人的社保号、驾照信息被拖走,公司股价腰斩,CEO引咎辞职。这起事件让Struts2的“漏洞之王”称号彻底坐实。
我见过太多开发团队把Struts2当成传家宝,一用就是七八年。问他们为什么不升级,回答惊人的一致:“改动太大,怕影响业务。”可他们没算过这笔账——一次安全审计的成本,可能比重构整个项目还高。更别提那些依赖老版本Struts2的遗留系统,它们像定时炸弹一样埋在企业的核心链路里,连扫描器都懒得碰,因为“扫出来也修不动”。
有个案例特别典型。某银行内部系统,登录模块用的就是Struts2,版本号停留在2014年。安全团队每年做渗透测试都会发现新漏洞,但每次的修复方案都是加WAF规则、封IP、限频率——全是治标不治本的招。直到有一年,攻击者用S2-057的变种直接绕过了所有防护,在内网横向移动了三天才被发现。事后复盘时,运维主管说了一句话:“我们不是在修漏洞,是在赌黑客哪天心情不好。”这话听着像玩笑,但透着深深的无力感。
现在Struts2的市场份额已经大不如前,Spring MVC和Spring Boot成了主流。但老系统不会自动消失,它们还在银行、航空公司、政务平台里默默运行。每次爆出新的Struts2 CVE,总有一批安全工程师熬夜打补丁、改配置、重启应用。这种循环什么时候是个头?除非企业愿意掏钱做真正的技术债清理,否则Struts2的阴影会一直笼罩在Java Web开发的上空。
说到底,Struts2的教训不是“框架不好”,而是“信任边界模糊”的代价。任何把用户输入当代码执行的框架,迟早会出事。今天Struts2的坑,明天可能出现在某个AI模型的提示词注入里——历史不会重复,但押韵得可怕。