logo
Published on

为什么 Google 会在 JSON 响应前添加 while(1);?

Authors
  • Name
    Twitter

在你请求 Google 的某些 JSON 数据时,你可能会看到这样的响应内容:while(1);。这并不是一个错误,而是 Google 用于防止 JSON 劫持 (JSON Hijacking) 的一种安全手段。本文将深入探讨这种方法的原理以及其他类似的防护措施。

什么是 JSON 劫持?

理论上,HTTP 响应内容应该受同源策略(Same Origin Policy)的保护:一个域名上的页面不能获得另一个域名上的信息(除非明确允许)。然而,攻击者可以通过例如 <script src=...><img> 标签在你的名义下请求其他域名的页面,但他们无法获取请求结果的任何信息(包括头信息和内容)。

举个例子,如果你访问了一个攻击者的网站,它本不应该读取你从 gmail.com 获取的邮件内容。然而,如果使用 <script> 标签请求 JSON 内容,JSON 会在攻击者控制的环境中作为 JavaScript 执行。如果攻击者能替换 Array 或 Object 构造器或其他对象构造中使用的方法,任何 JSON 数据都可能经过攻击者的代码,从而泄露信息。

值得注意的是,问题出现在 JSON 被当作 JavaScript 执行时,而不是解析时。

防止 JSON 劫持的多种对策

确保 JSON 永远不会被执行

Google 通过在 JSON 数据前添加 while(1); 语句,确保了这些数据永远不会被当作 JavaScript 执行。只有合法的页面才能获取完整内容,去掉 while(1); 并将剩余内容解析为 JSON。类似的方法也出现在 Facebook 中,例如使用 for(;;);

确保 JSON 不是有效的 JavaScript

同样地,在 JSON 前添加无效标记,如 &&&START&&&,确保其永远不会被执行为 JavaScript。

始终返回带有外部对象的 JSON

这是 OWASP 推荐 的一种方法,保护 JSON 免受劫持,且相对较少侵入性。

类似于之前的对策,这种方法确保 JSON 永远不会被当作 JavaScript 执行。一个外层是对象的有效 JSON,在不被包含时,是无效的 JavaScript,因为 {} 会被解释为代码块:

eval('{"foo":"bar"}')
// SyntaxError: Unexpected token :

然而,这在 JSON 中是有效的:

JSON.parse('{"foo":"bar"}')
// Object {foo: "bar"}

所以,确保你的 JSON 响应的顶层始终是一个对象,并确保 JSON 不是有效的 JavaScript,同时仍然是有效的 JSON。

方法对比

OWASP 的方法较少侵入性,因为它不需要客户端库的更改,并传输有效的 JSON。尽管目前和未来的浏览器漏洞是否会打破这种防护还有待观察。正如 @oriadam 所指出的,数据是否可能在解析错误时通过错误处理泄露(例如 window.onerror)也不确定。

Google 的方法则要求使用客户端库来支持自动反序列化,相较于浏览器漏洞,它可以被认为是更安全的。但这两种方法都需要在服务器端进行修改,以避免开发者无意中发送易受攻击的 JSON 数据。