为什么 Google 会在其 JSON 响应前面添加 while(1);?
为什么 Google 要将
while(1);
添加到其(私有)JSON 响应中?
例如,以下是在 Google 日历 中打开和关闭日历时的响应:
while (1);
[
['u', [
['smsSentFlag', 'false'],
['hideInvitations', 'false'],
['remindOnRespondedEventsOnly', 'true'],
['hideInvitations_remindOnRespondedEventsOnly', 'false_true'],
['Calendar ID stripped for privacy', 'false'],
['smsVerifiedFlag', 'true']
]]
]
我认为这是为了防止人们在其上执行
eval()
,但您真正需要做的就是替换
while
,然后就可以了。我认为 eval 预防是为了确保人们编写安全的 JSON 解析代码。
我也在其他几个地方看到过这种用法,但在 Google(邮件、日历、通讯录等)中使用得更多。奇怪的是,
Google Docs
以
&&&START&&&
开头,而 Google 通讯录似乎以
while(1); &&&START&&&
开头。
这是怎么回事?
它可以防止 JSON 劫持 ,这是一个重大的 JSON 安全问题,自 2011 年起,该问题已在所有主流浏览器中通过 ECMAScript 5 正式 修复 。
人为示例:假设 Google 有一个 URL,如
mail.google.com/json?action=inbox
,它会以 JSON 格式返回收件箱中的前 50 封邮件。由于同源策略,其他域中的恶意网站无法发出 AJAX 请求来获取此数据,但它们可以通过
<script>
标记包含 URL。该 URL 使用
您的
cookie 进行访问,并且通过
覆盖全局数组构造函数或访问器方法
,它们可以在设置对象(数组或哈希)属性时调用一个方法,从而允许它们读取 JSON 内容。
while(1);
或
&&&BLAH&&&
可防止这种情况发生:
mail.google.com
上的 AJAX 请求将具有对文本内容的完全访问权限,并可以将其删除。但是,插入
<script>
标签会盲目执行 JavaScript 而不进行任何处理,从而导致无限循环或语法错误。
这并不能解决 跨站请求伪造 的问题。
它可以防止通过 JSON 劫持泄露响应。
理论上,HTTP 响应的内容受同源策略保护:一个域中的页面无法从另一个域中的页面获取任何信息(除非明确允许)。
攻击者可以代表您请求其他域上的页面,例如通过使用
<script src=...>
或
<img>
标记,但无法获取有关结果的任何信息(标题、内容)。
因此,如果您访问攻击者的页面,它无法读取来自 gmail.com 的电子邮件。
除非使用脚本标记请求 JSON 内容时,JSON 会在攻击者的控制环境中作为 JavaScript 执行。如果攻击者可以替换 Array 或 Object 构造函数或对象构造过程中使用的其他方法,JSON 中的任何内容都将通过攻击者的代码,并被泄露。
请注意,这种情况发生在 JSON 作为 JavaScript 执行时,而不是解析时。
有多种对策:
确保 JSON 永远不会执行
通过在 JSON 数据之前放置
while(1);
语句,Google 可确保 JSON 数据永远不会作为 JavaScript 执行。
只有合法页面才能真正获取整个内容,删除
while(1);
,并将剩余部分解析为 JSON。
例如,在 Facebook 上看到过
for(;;);
之类的东西,结果相同。
确保 JSON 不是有效的 JavaScript
同样,在 JSON 之前添加无效令牌,例如
&&&START&&&
,确保它永远不会被执行。
始终返回外部带有对象的 JSON
这是 OWASP 推荐的方法 ,以防止 JSON 劫持,并且侵入性较低。
与之前的对策类似,它确保 JSON 永远不会作为 JavaScript 执行。
有效的 JSON 对象,如果没有被任何东西包围,在 JavaScript 中是无效的,因为
{ }
被解释为代码块:
eval('{"foo":"bar"}')
// SyntaxError: Unexpected token :
但是这是有效的JSON:
JSON.parse('{"foo":"bar"}')
// Object {foo: "bar"}
因此,请确保始终在响应的顶层返回一个对象,并确保 JSON 不是有效的 JavaScript,但仍然是有效的 JSON。
正如 @hvd 在评论中指出的那样,空对象
{
是有效的 JavaScript,并且知道对象为空本身可能就是有价值的信息。
上述方法的比较
OWASP 方法的侵入性较小,因为它不需要更改客户端库,并且可以传输有效的 JSON。但是,不确定过去或将来的浏览器错误是否能够破坏这一点。正如 @oriadam 所指出的那样,尚不清楚数据是否会通过错误处理(例如 window.onerror)在解析错误中泄露。
Google 的方法需要客户端库才能支持自动反序列化,并且就浏览器错误而言可以认为更安全。
这两种方法都需要服务器端进行更改,以避免开发人员意外发送有漏洞的 JSON。
这是为了确保其他网站无法使用恶意手段窃取您的数据。例如,通过
替换数组构造函数
,然后通过
<script>
标记包含此 JSON URL,恶意第三方网站可以从 JSON 响应中窃取数据。通过在开头放置
while(1);
,脚本将挂起。
另一方面,使用 XHR 和单独的 JSON 解析器的同一站点请求可以轻松忽略
while(1);
前缀。