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

2022-08-30 02:20:48

我正在使用Backbone.js和Tornado Web服务器。在 Backbone 中接收集合数据的标准行为是作为 JSON 数组发送。

另一方面,Tornado的标准行为是由于以下漏洞而不允许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劫持”?但是由于接受的答案似乎没有回答这个问题 - 我认为是时候再次询问它并获得一些更清晰的解释了。


答案 1

不可以,无法再捕获传递给 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>

它通过短形式和长形式覆盖并添加 setter 并测试数组和对象的初始化。window.ArrayObject.prototype.foo

ES4 规范在第 1.5 节中“要求使用 Object 和 Array 的全局标准绑定来构造对象和数组初始值设定项的新对象”,并在 Implementation Precedent 中指出“Internet Explorer 6、Opera 9.20 和 Safari 3 不考虑 Object 和 Array 的本地或全局重新绑定,而是使用原始的对象和数组构造函数。这保留在 ES5 的第 11.1.4 节中

Allen Wirfs-Brock解释说,ES5还指定了对象初始化不应该触发 setter,因为它使用DefineOwnProperty。MDN:使用对象指出,“从 JavaScript 1.8.1 开始,在对象和数组初始值设定项中设置属性时不再调用 setter。此问题已在 V8 问题 1015 中得到解决。


答案 2