JSON 劫持在现代浏览器中仍然是一个问题吗?

我正在使用 Backbone.js 和龙卷风网络服务器。在 Backbone 中接收收集数据的标准行为是作为 JSON 数组发送。

另一方面,由于下面的漏洞,龙卷风的标准行为是不允许 JSON 数组的:

Http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx

一个相关的问题是: Http://haacked.com/archive/2009/06/25/json-hijacking.aspx

对我来说,当 JSON 实际上是一个对象列表时,不必将它包装在对象中,这种感觉更自然。

我无法在现代的浏览器中重现这些攻击(比如当前的 Chrome、 Firefox、 Safari 和 IE9)。与此同时,我无法证实现代浏览器已经解决了这些问题。

为了确保我不会被任何可能的糟糕编程技能或糟糕的谷歌技能所误导:

在现代浏览器中,这些 JSON 劫持攻击仍然是一个问题吗?

(注意: 很抱歉可能重复到: 有可能做的 JSON 劫持在现代浏览器?,但由于接受的答案似乎没有回答这个问题-我认为是时候再问一次,并得到一些更清楚的解释。)

43511 次浏览

不,在 Firefox 21、 Chrome 27或 IE 10中不再可能捕获传递给 []{}构造函数的值。下面是一个基于 http://www.thespanner.co.uk/2011/05/30/json-hijacking/中描述的主要攻击的小测试页面:

(http://jsfiddle.net/ph3Uv/2/)

var capture = function() {
var ta = document.querySelector('textarea')
ta.innerHTML = '';
ta.appendChild(document.createTextNode("Captured: "+JSON.stringify(arguments)));
return arguments;
}
var original = Array;


var toggle = document.body.querySelector('input[type="checkbox"]');
var toggleCapture = function() {
var isOn = toggle.checked;
window.Array = isOn ? capture : original;
if (isOn) {
Object.defineProperty(Object.prototype, 'foo', {set: capture});
} else {
delete Object.prototype.foo;
}
};
toggle.addEventListener('click', toggleCapture);
toggleCapture();


[].forEach.call(document.body.querySelectorAll('input[type="button"]'), function(el) {
el.addEventListener('click', function() {
document.querySelector('textarea').innerHTML = 'Safe.';
eval(this.value);
});
});
<div><label><input type="checkbox" checked="checked"> Capture</label></div>
<div><input type="button" value="[1, 2]" /> <input type="button" value="Array(1, 2);" /> <input type="button" value="{foo: 'bar'}" /> <input type="button" value="({}).foo = 'bar';" /></div>
<div><textarea></textarea></div>

它覆盖 window.Array并向 Object.prototype.foo添加一个 setter,并通过短形式和长形式测试初始化数组和对象。

在第1.5节中,ES4规格“要求对象和数组的全局、标准绑定用于为对象和数组初始化器构造新的对象”,并在实现先例中指出,“ Internet Explorer 6、 Opera 9.20和 Safari 3不尊重对象和数组的本地或全局重绑定,而是使用原始的对象和数组构造器。”这保留在 ES5第11.1.4节中。

Allen Wirfs-Brock 解释说 ES5还指定对象初始化不应触发 setter,因为它使用 Definition eOwnProperty。MDN: 使用对象指出: “从 JavaScript1.8.1开始,在对象和数组初始化器中设置属性时不再调用 setter。”这是在 V8第1015期中提到的。