易受攻击的javascript库漏洞
2018年,易受一个叫Sam Curry的攻击安全研究员在测试某航空公司的网站时,发现页面加载了一个三年前就停止维护的漏洞JavaScript库——jQuery 1.7。他只用了一个已知的易受跨站脚本漏洞,就拿到了管理后台的攻击会话令牌。航空公司花了四个月才修复。漏洞这不是易受孤例,类似的攻击事情每天都在发生。
JavaScript库的漏洞漏洞之所以危险,核心原因只有一个:开发者引入它们时,易受往往只关心功能能不能跑通,攻击不关心它上一次更新是漏洞什么时候。npm生态里有超过200万个包,易受其中大量依赖链深达十几层。攻击你装了一个UI组件库,漏洞它依赖一个日期处理库,那个库又依赖一个工具函数库,最后一层可能是一个2016年就没再维护过的包。攻击者不需要攻破你的代码,只需要攻破你依赖树里最弱的那个节点。
具体来说,漏洞分几种典型情况。
一种是原型污染。lodash在4.17.12之前的版本存在这个问题。攻击者通过构造特殊的JSON输入,可以修改JavaScript对象的原型链,进而控制整个应用的逻辑。2019年,有安全团队发现大量使用lodash的API网关可以被这种方式绕过权限校验。修复方式很简单——升级到4.17.21。但问题是,很多项目的package-lock.json锁死了旧版本,没人去动它。
另一种是正则表达式拒绝服务,简称ReDoS。moment.js在解析特定格式的日期字符串时,会触发灾难性回溯。一个几十字节的输入就能让CPU飙到100%,持续好几秒。如果这个解析接口暴露在公网,攻击者发几百个并发请求就能让服务器瘫痪。moment.js官方在2020年宣布停止开发新功能,建议迁移到dayjs或date-fns,但直到今天,npm上moment的周下载量仍然超过1500万次。
还有一种更隐蔽的——供应链投毒。event-stream这个包在2018年被植入恶意代码,目标是窃取比特币钱包的私钥。攻击者先成为维护者,然后添加了一个叫flatmap-stream的依赖,里面藏着经过混淆的payload。这个包被大量知名项目间接引用,包括一些IDE插件。整个攻击链条设计得非常精细,普通代码审查根本看不出来。
那为什么这些问题反复出现?我观察到一个很实际的原因:前端开发者对依赖更新的敏感度远低于后端。后端有Dependabot、Snyk这类工具自动提PR,CI流程里也会跑安全扫描。但很多前端项目连npm audit都不看,觉得“能跑就行”。另一个原因是破坏性变更的恐惧。升级一个主版本号,可能意味着几十个API要改,测试要重写,谁都不想碰。
我的判断是,这个问题不会因为工具进步就自动消失。Sonatype的报告显示,2023年恶意JavaScript包的数量同比增长了超过200%。攻击者的成本在降低,而防御者的惰性没变。如果你现在维护着一个前端项目,最实际的动作是:打开package.json,把那些两年以上没更新过的依赖列出来,逐个查CVE。别等出了事再补。








