- Published on
为什么 Google 会在 JSON 响应前添加 while(1);?
- Authors
- Name
在你请求 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 数据。