Object.getPrototypeOf无法用于闭包本身,因闭包非对象;需对闭包引用的具体对象(如this、参数或外层变量)实时检查其原型,用Object.is比对预存的原始原型引用,并结合Proxy拦截或前置校验增强安全性。

Object.getPrototypeOf 无法用于“闭包对象”本身,因为闭包不是对象,也不具备原型链;它只是函数作用域的静态绑定机制。所谓“闭包中捕获的外部实例”,实际是指闭包内部引用的一个对象(比如 this、参数或外层变量)。甄别该对象的原型是否被恶意重绑定,关键在于**在访问时实时检查其原型,而非依赖闭包创建时的状态**。
明确目标:你要监控的是哪个对象?
闭包不会“持有”原型,只持有对某个对象的引用。你需要先确认这个被引用的对象是谁:
- 是调用时的
this(如事件回调中的实例)? - 是外层函数传入的参数(如
function makeHandler(instance) { return () => instance.method(); })? - 是模块顶层或父作用域定义的实例变量?
只有明确了具体对象,才能对其调用 Object.getPrototypeOf(obj) 进行比对。
安全比对:用 Object.is 或 === 固定参考原型
不能仅靠 obj.__proto__ === SomeClass.prototype,因为 __proto__ 可被改写,且非标准。正确做法是:在对象创建后、闭包生成前,预先保存其原始原型引用:
-
推荐方式:在实例化后立即缓存
const originalProto = Object.getPrototypeOf(instance); - 在闭包内每次使用前检查:
if (!Object.is(Object.getPrototypeOf(instance), originalProto)) { throw new Error("Prototype tampered"); } - 避免用
===比较不同上下文中的SomeClass.prototype(跨 iframe 或动态加载时可能不等)
防御性封装:把检查逻辑注入访问路径
不要等到执行方法时才检查——攻击者可能在调用前瞬间篡改原型。应将校验前置到属性访问或方法调用入口:
- 用代理(Proxy)包装目标实例,拦截
get和apply,每次触发都校验原型 - 若无法用 Proxy,可在闭包返回的函数中强制校验,例如:
return function guardedCall() {<br> if (!Object.is(Object.getPrototypeOf(instance), originalProto)) throw ...;<br> return instance.method.apply(instance, arguments);<br>};
注意边界:哪些情况无法靠 getPrototypeOf 检测?
Object.getPrototypeOf 只反映当前 [[Prototype]] 值,但以下行为它无法捕捉:
- 攻击者用
Object.setPrototypeOf(obj, null)清空原型(仍可检测,因结果不等于原始值) - 通过
obj.constructor.prototype = {...}修改构造函数的prototype属性(不影响已有实例的[[Prototype]]) - 用
Object.defineProperty(obj, '__proto__', { writable: false })锁死但已篡改过的原型(此时getPrototypeOf返回的仍是篡改后的值) - 实例本身是用
Object.create(null)创建的(无原型,getPrototypeOf返回null)
因此,单纯依赖 getPrototypeOf 不够,需结合不可变设计(如冻结构造函数、禁止修改 prototype)、运行时沙箱或完整原型链快照(如递归遍历 getPrototypeOf 直到 null)来增强鲁棒性。

















