关键在于识别原型链是否偏离预期结构,可通过比对初始化时保存的原型链快照、校验内置方法是否为原生实现、验证构造器与原型双向一致性、检查冻结/密封状态等多手段综合判断。

直接检测原型链是否被第三方修改,关键不是“发现修改行为”,而是“识别当前原型链是否偏离了预期结构”。JavaScript 本身不提供原型链变更的监听机制,但可以通过比对基准快照、检查内置属性一致性、验证构造器与原型关系等手段判断是否已被篡改。
保存并比对原型链快照
在应用初始化早期(如库加载前、业务逻辑执行前),手动记录关键对象(Object、Array、Function 等)的原型链结构作为可信基准:
- 用
Object.getPrototypeOf()逐层获取原型,生成原型路径数组(如[Array.prototype, Object.prototype, null]) - 将该路径序列化为字符串或哈希值(如
JSON.stringify(path)或crc32(path.join('|'))),存入只读变量或闭包中 - 运行时重新采集路径并比对——若不一致,说明至少某层原型被替换(如
Array.prototype = {})
检查内置原型的不可枚举属性和方法是否存在
第三方代码常通过覆盖原型方法(如 Array.prototype.push)或删除属性来劫持行为。可校验关键方法是否仍为原生实现:
- 用
typeof Array.prototype.push === 'function'确保方法未被设为undefined或非函数值 - 用
Array.prototype.push.toString().includes('[native code]')判断是否仍为原生函数(注意:部分环境可能屏蔽该字符串,需配合其他方式) - 检查
Object.prototype.hasOwnProperty是否仍可用且未被重写(它是几乎所有对象属性检测的基础)
验证构造器与原型的双向一致性
正常情况下,obj.constructor.prototype === Object.getPrototypeOf(obj)。若原型被篡改但构造器未同步更新,该等式会失效:
- 对任意对象
obj,执行obj.constructor && Object.getPrototypeOf(obj) === obj.constructor.prototype - 若返回
false,常见于第三方重写了obj.constructor.prototype却未修正obj.constructor,或直接替换了__proto__ - 特别关注全局构造器(如
Array)的prototype是否仍指向原始Array.prototype
使用 Object.isFrozen() 和 Object.isSealed() 辅助判断
虽然不能直接检测修改,但可评估原型对象是否处于受保护状态:
-
Object.isFrozen(Object.prototype)在严格模式或现代环境应为true;若返回false,说明它曾被解冻并可能被修改 - 检查
Object.prototype是否被添加了意外属性:Object.getOwnPropertyNames(Object.prototype).length > 0(标准下应仅含极少数内置属性) - 注意:此法仅作辅助,因冻结/密封状态本身也可能被解除
不复杂但容易忽略的是时机——快照必须在任何第三方脚本执行前完成,否则基准已失真。结合多种检查能显著提升检测鲁棒性,但无法 100% 拦截所有隐蔽篡改(如 Proxy 代理原型)。核心思路是建立可信锚点,再以它为标尺衡量现状。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











