JSON.parse本身无安全校验,会原样解析__proto__等敏感键导致原型链污染;防护需在解析后主动清洗、使用reviver过滤、避免危险合并操作或采用Object.create(null)。

JSON.parse 本身没有“安全性校验功能”,它不会自动过滤或拦截 __proto__、constructor 等敏感键名。所谓“利用其校验功能规避污染”是一种常见误解——原生 JSON.parse 会原样还原这些键,正是原型链污染的起点之一。
为什么 JSON.parse 不能防污染?
JSON 规范允许对象包含任意字符串作为键名,__proto__ 在语法上完全合法。当解析含该字段的字符串时:
-
JSON.parse('{"__proto__": {"isAdmin": true}}')返回一个普通对象,其键就是"__proto__" - 若后续用这个结果做深合并(如
_.merge({}, parsed)),旧版 lodash 会把__proto__当作路径递归赋值,最终写入Object.prototype - 即使不合并,若手动遍历赋值(
for (let k in parsed) target[k] = parsed[k]),且未跳过敏感键,同样触发污染
真正有效的防护方式
必须在 JSON.parse 之后、数据落地前主动干预,不能依赖 parse 自身:
-
解析后立即清洗:递归遍历解析结果,删除所有
__proto__、constructor、prototype及其大小写变体(如__PROTO__) -
用安全的替代解析逻辑:改用带 reviver 的
JSON.parse(str, (k, v) => k === '__proto__' ? undefined : v),直接在解析过程中屏蔽 -
避免后续危险操作:不使用
lodash.merge、_.set等默认接受原型键的函数;改用Object.assign({}, data)(仅浅拷贝)或structuredClone(data)(现代环境) -
源头隔离:关键配置对象不用
{},改用Object.create(null)—— 它没有__proto__,天然免疫
一个实用的清洗函数示例
适用于解析后立即处理不可信 JSON:
立即学习“Java免费学习笔记(深入)”;
function sanitizeProto(obj) {if (obj !== null && typeof obj === 'object') {
Object.keys(obj).forEach(key => {
if (/^__proto__$|^constructor$|^prototype$/i.test(key)) {
delete obj[key];
} else {
sanitizeProto(obj[key]);
}
});
}
return obj;
}
调用:const safeData = sanitizeProto(JSON.parse(userInput));


















