防止原型链被恶意篡改的关键是切断污染入口、限制修改权限、隔离影响范围;需冻结原生原型、禁用敏感操作、用继承或工具函数替代原型扩展,并结合构建期扫描与运行时监控。

防止原型链被恶意篡改,关键不是“加固链条”,而是**切断污染入口、限制修改权限、隔离影响范围**。原生原型(如 Object.prototype、Array.prototype)是全局契约,一旦被改,所有代码都会受影响——这不是 bug,是设计使然;所以防御思路必须前置、主动、有层次。
冻结关键原型对象
在应用启动最早期(第三方脚本加载前),用 Object.freeze() 锁定常用内置构造函数的 prototype:
Object.freeze(Object.prototype)Object.freeze(Array.prototype)Object.freeze(String.prototype)Object.freeze(Number.prototype)Object.freeze(Boolean.prototype)Object.freeze(Function.prototype)
冻结后,任何对这些原型添加、删除或重写属性的操作,在严格模式下会抛出 TypeError,非严格模式下则静默失败。这是最直接、成本最低的一道防线。
禁用原型污染敏感操作
很多污染并非手动修改,而是通过不安全的数据合并触发的。要重点拦截以下行为:
- 禁止使用
lodash.merge、_.set等递归赋值工具处理不可信输入(如 URL 参数、用户 JSON) - 解析外部 JSON 后,若需合并进配置对象,先用白名单过滤键名,明确排除
"__proto__"、"constructor"、"prototype"及其大小写变体 - 避免手写递归
deepAssign函数,除非显式跳过原型相关字段;现代环境优先用structuredClone()做深拷贝
用继承替代补丁,用工具函数替代原型扩展
想增强能力?别动原生原型:
- 需要数组新方法?定义
const last = arr => arr?.[arr.length - 1];,而不是Array.prototype.last = ... - 需要定制行为?用
class MyList extends Array创建子类,新方法只作用于new MyList()实例 - 模块内临时扩展?用
Symbol('myMethod')挂载,避免命名冲突且不可枚举
运行时监控与构建期拦截
防御不能只靠开发自觉:
- 在 CI/CD 流程中加入代码扫描规则,禁止出现
.prototype.对原生构造器的赋值语句(如Array.prototype.map =) - 生产环境可注入轻量监控脚本,定期检查关键原型属性是否被意外覆盖(如对比
Object.prototype.toString.toString()是否仍为原生函数) - Node.js 服务启动时加
--disable-proto=throw参数,强制拦截通过__proto__修改原型的行为
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











