Object.getPrototypeOf是只读诊断工具,用于精准识别原型链污染节点而非修复;它返回对象真实[[Prototype]]值,可递归遍历校验每层原型是否被非法扩展,并为冻结、重建、拦截等修复动作提供依据。
Object.getPrototypeOf 本身不用于“实现污染”,而是用于检测、遍历和验证原型链——它是一个只读的诊断工具。所谓“深度修复原型链污染”,核心不是用它来操作,而是靠它精准识别被篡改的原型节点,再配合其他安全手段清理或阻断污染路径。
明确 Object.getPrototypeOf 的定位
该方法返回对象真实的
[[Prototype]]
值,不可写、不触发副作用,是判断原型归属的黄金标准:
它不会修改任何原型,也不能“修复”污染;它的作用是告诉你“当前对象真正连在哪”
例如:
恒为 true,哪怕
已被注入,这个等式依然成立——污染发生在原型对象上,而非链接关系本身
若发现
但
或
,就提示原型对象可能已被污染
递归遍历原型链以定位污染源头
利用
向上递归,可系统性检查每层原型是否被非法扩展(如意外出现
、
、
等敏感键):
从目标对象开始,逐级获取原型:
对每一层
,执行安全属性扫描:只允许存在原生自有属性(可用
获取),过滤掉用户注入的非常规键(如
、
被重写、
出现在非原始包装对象上)
重点校验顶层原型:
必须为 true;若为 false,说明
的原型被篡改,属严重逃逸
结合污染修复的三类关键动作
仅靠
无法修复,但它是触发修复的前提。真实修复需组合以下操作:
冻结污染原型
:对已确认被污染的原型(如
),立即调用
阻止进一步写入(注意:freeze 不可逆,且对已有属性无效,仅防新增)
重建干净实例
:避免复用可能携带污染的对象。用
创建无原型基础的对象,或用
显式绑定可信原型
拦截危险合并逻辑
:在
、
类函数中,对每个 key 做白名单校验——若 key 是
、
、
,直接跳过或报错,不进入递归分支
一个轻量修复辅助函数示例
该函数不直接“修复”,而是返回污染证据,供后续决策:
调用
可快速定位哪一层原型开始异常,再针对性 freeze 或隔离。
Object.getPrototypeOf({}) === Object.prototypeObject.prototype.isAdmin = trueObject.getPrototypeOf(obj) === Object.prototypeobj.constructor !== Objectobj.toString !== Object.prototype.toStringObject.getPrototypeOf__proto__constructortoStringlet p = obj; while (p = Object.getPrototypeOf(p)) { /* 检查 p */ }pObject.getOwnPropertyNames(p)isAdmintoString__proto__Object.getPrototypeOf(Object.prototype) === nullObject.prototypeObject.getPrototypeOfObject.prototypeObject.freeze(Object.prototype)Object.create(null)Object.setPrototypeOf({}, cleanProto)mergeassign"__proto__""constructor""prototype"function inspectPrototypeChain(obj, depth = 0) {
if (depth > 10) return { error: 'Prototype chain too deep' };
const proto = Object.getPrototypeOf(obj);
if (proto === null) return { clean: true };
// 检查当前原型是否含高危属性
const keys = Object.getOwnPropertyNames(proto);
const dangerous = keys.filter(k => ['proto', 'constructor', 'prototype'].includes(k) ||
k.startsWith('__') || k === 'toString');
if (dangerous.length > 0) {
return {
polluted: true,
level: depth,
prototype: proto,
dangerousKeys: dangerous
};
}
return inspectPrototypeChain(proto, depth + 1);
}
inspectPrototypeChain(userInput)