青灵
38.24M · 2026-03-07
在前端和 Node.js 开发中,JSON.parse() 几乎无处不在:
const data = JSON.parse(localStorage.getItem('user'));
const config = JSON.parse(req.body.payload);
const settings = JSON.parse(fs.readFileSync('config.json'));
简洁、直接、好用——但极其危险。
如果你没有对输入做任何校验就调用 JSON.parse(),你正在为应用打开一扇“任意代码执行”的后门。
今天,我们就来揭开 JSON.parse() 背后的安全雷区,并告诉你如何用更安全、更现代的方式处理 JSON 数据。
这是 JSON.parse() 最臭名昭著的安全漏洞之一。
虽然原生 JSON.parse() 本身不会执行代码,但它会忠实地还原对象结构——包括 __proto__ 和 constructor.prototype 这类特殊属性。
来看一个真实攻击载荷:
const userInput = '{"__proto__":{"isAdmin":true}}';
const obj = {};
JSON.parse(userInput, (key, value) => {
obj[key] = value;
return value;
});
console.log({}.isAdmin); // true!全局对象被污染!
如果这段代码出现在你的登录逻辑、权限校验或配置合并中,攻击者就能:
isAdmin: true);exec: 'rm -rf /');恶意构造的 JSON 字符串可导致内存爆炸或CPU 耗尽:
// 深度嵌套攻击
const evil = '{"a":{"a":{"a":{"a":{"a":{"a": ... }}}}}}';
// 或超大数组
const evil2 = '[1,1,1,...,1]' // 1000 万个元素
调用 JSON.parse(evil) 可能:
在 API 接口或 Webhook 处理中,这等于把“关机按钮”交给了攻击者。
在解析前先检查字符串长度:
function safeParse(str, maxSize = 1024 * 100) { // 100KB
if (typeof str !== 'string' || str.length > maxSize) {
throw new Error('Input too large');
}
return JSON.parse(str);
}
__proto__)使用 reviver 函数过滤敏感属性:
function secureJSONParse(str) {
return JSON.parse(str, (key, value) => {
if (key === '__proto__' || key === 'constructor') {
throw new Error('Disallowed key in JSON');
}
return value;
});
}
这才是现代 JS 工程的最佳实践!
import { z } from 'zod';
const UserSchema = z.object({
id: z.number(),
name: z.string(),
email: z.string().email(),
isAdmin: z.boolean().optional(),
});
function parseUser(jsonStr: string) {
const raw = secureJSONParse(jsonStr);
return UserSchema.parse(raw); // 自动校验 + 类型推导
}
优势:
在服务端,如果你从以下来源解析 JSON,风险更高:
req.body)务必在解析前做来源校验 + 结构校验 + 大小限制三重保险!
JSON.parse() 不是“坏 API”,但它是一把没有保险的枪。
在现代 Web 开发中,信任任何用户输入 = 自毁程序。
下次当你写下 JSON.parse(someString) 时,请自问:
如果答案不确定,请立即切换到 Zod / Joi + 安全解析函数 的组合。
转发给那个还在裸用 JSON.parse() 的队友吧!
各位互联网搭子,要是这篇文章成功引起了你的注意,别犹豫,关注、点赞、评论、分享走一波,让我们把这份默契延续下去,一起在知识的海洋里乘风破浪!