为什么人们在JSON响应前加上像“throw 1; ”和“for(;;);”这样的代码?
为什么人们在JSON响应前加上像“throw 1; ”和“for(;;);”这样的代码?
这个问题在此处已经有答案:
可能是重复问题:
为什么Google在他们的JSON响应中加上while(1);?
Google返回的JSON如下:
throw 1;{ foo: bar}
Facebook的ajax返回的JSON如下:
for(;;); {"error":0,"errorSummary": ""}
- 为什么他们要放会停止执行并使JSON无效的代码?
- 如果它是无效的并且尝试评估它会使其崩溃,他们如何解析它?
- 他们只是从字符串中删除它(似乎很耗费资源)?
- 这样做有什么安全优势吗?
回应它是出于安全目的:
如果网络爬虫在另一个域上,他们将不得不使用script
标签来获取数据,因为XHR不能跨域工作。即使没有for(;;);
,攻击者如何获取数据?它没有被分配到变量中,因此不会被垃圾回收站回收,因为它没有任何引用。
基本上,要跨域获取数据,他们必须执行:
但即使没有崩溃的脚本,攻击者也无法使用任何JSON数据,除非将其分配给可以全局访问的变量(在这些情况下没有)。崩溃的代码实际上什么也没做,因为即使没有它,他们也必须使用服务器端脚本在他们的站点上使用数据。
考虑一下,在检查了你的GMail帐户之后,你访问了我的邪恶页面:
现在会发生的事情是来自Google的Javascript代码将被发布到我的邪恶站点上--提问者认为这些代码是良性的并且不会立即超出范围--假设在脚本标记中请求的URL发送(因为您的浏览器将呈现正确的cookie,Google将正确地认为您已登录您的收件箱):
({ messages: [ { id: 1, subject: 'Super confidential information', message: 'Please keep this to yourself: the password is 42' },{ id: 2, subject: 'Who stole your password?', message: 'Someone knows your password! I told you to keep this information to yourself! And by this information I mean: the password is 42' } ] })
现在,我将将此对象的序列化版本发布到我的邪恶服务器上。 谢谢!防止发生这种情况的方法是使您的JSON响应变复杂,并在您可以操作该数据的同一域中去掉它们的复杂性。如果您喜欢这个答案,请看一下bobince发布的答案。
即使没有
for(;;);
,攻击者如何获取数据?
攻击基于更改内置类型的行为,特别是 Object
和 Array
,通过更改它们的构造函数或其 prototype
。然后,当目标 JSON 使用 {...}
或 [...]
构造时,它们将成为攻击者自己的版本这些对象,具有潜在的意外行为。
例如,你可以将一个 setter 属性劫持到 Object
中,它将泄露在对象字面量中编写的值:
Object.prototype.__defineSetter__('x', function(x) { alert('Ha! I steal '+x); });
然后当指向使用该属性名称的 JSON 的 时:
{"x": "hello"}
将泄露出值 "hello"
。
数组和对象字面量导致调用设置器的方式具有争议。Firefox 在版本 3.5 中删除了该行为,以回应对高知名度网站的公开攻击。然而,在撰写本文时,Safari(4)和 Chrome(5)仍然容易受到攻击。
所有浏览器现在都不允许的另一种攻击是重定义构造函数:
Array= function() { alert('I steal '+this); }; [1, 2, 3]
目前,IE8 对属性的实现(基于 ECMAScript 第五版标准和 Object.defineProperty
)还不能用于 Object.prototype
或 Array.prototype
。
但是,除了保护过去的浏览器外,也可能会有 JavaScript 扩展导致类似的更多潜在泄漏,在这种情况下,反间谍器(chaff)也应该防止这些泄漏。