为什么谷歌会在(1);他们的(私有)JSON响应?

例如,在Google calendar中打开和关闭日历时有一个响应:

while (1);
[
  ['u', [
    ['smsSentFlag', 'false'],
    ['hideInvitations', 'false'],
    ['remindOnRespondedEventsOnly', 'true'],
    ['hideInvitations_remindOnRespondedEventsOnly', 'false_true'],
    ['Calendar ID stripped for privacy', 'false'],
    ['smsVerifiedFlag', 'true']
  ]]
]

我认为这是为了防止人们对它进行求值(),但你真正需要做的就是替换while,然后就可以设置了。我假设eval预防是为了确保人们编写安全的JSON解析代码。

我也在其他几个地方看到过这种用法,但在谷歌(邮件、日历、联系人等)中更是如此。奇怪的是,谷歌文档以&&&START&&开头,而谷歌联系人似乎以while开头(1)&&&开始&&&。

这是怎么回事?


当前回答

这是为了确保某些其他网站不会使用卑鄙的手段来窃取您的数据。例如,通过替换数组构造函数,然后通过<script>标记包含此JSON URL,恶意第三方站点可以从JSON响应中窃取数据。通过放置一段时间(1);在开始时,脚本将挂起。

另一方面,使用XHR和单独的JSON解析器的同一站点请求可以很容易地忽略while(1);前缀

其他回答

身份验证到位后,JSON劫持保护可能需要各种形式。Google将while(1)附加到JSON数据中,因此如果任何恶意脚本对其求值,则恶意脚本将进入无限循环。

参考资料:网络安全测试指南:快速发现问题的系统技术

这是为了确保某些其他网站不会使用卑鄙的手段来窃取您的数据。例如,通过替换数组构造函数,然后通过<script>标记包含此JSON URL,恶意第三方站点可以从JSON响应中窃取数据。通过放置一段时间(1);在开始时,脚本将挂起。

另一方面,使用XHR和单独的JSON解析器的同一站点请求可以很容易地忽略while(1);前缀

它防止通过JSON劫持泄露响应。

理论上,HTTP响应的内容受到同源策略的保护:来自一个域的页面无法从另一个域上的页面获取任何信息(除非明确允许)。

攻击者可以代表您请求其他域上的页面,例如使用<script src=…>或<img>标记,但它无法获得有关结果的任何信息(标题、内容)。

因此,如果您访问攻击者的页面,它将无法从gmail.com读取您的电子邮件。

除了使用脚本标记请求JSON内容时,JSON在攻击者控制的环境中作为JavaScript执行。如果攻击者可以替换Array或Object构造函数或对象构建过程中使用的其他方法,JSON中的任何内容都会通过攻击者的代码,并被泄露。

注意,当JSON作为JavaScript执行时会发生这种情况,而不是在解析时。

有多种应对措施:

确保JSON永远不会执行

通过放置一段时间(1);语句之前,Google确保JSON数据永远不会作为JavaScript执行。

只有合法的页面才能真正获得全部内容,去掉while(1);,并将剩余部分解析为JSON。

类似于(;;);例如,在Facebook上也看到了同样的结果。

确保JSON不是有效的JavaScript

类似地,在JSON之前添加无效的标记,如&&&START&&,可以确保它永远不会被执行。

始终返回外部带有Object的JSON

这是OWASP推荐的防止JSON劫持的方法,也是侵入性较小的方法。

与前面的对策类似,它确保JSON永远不会作为JavaScript执行。

一个有效的JSON对象,如果没有被任何东西括起来,在JavaScript中是无效的,因为{}被解释为一个代码块:

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

然而,这是有效的JSON:

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

因此,确保始终在响应的顶层返回Object,并确保JSON不是有效的JavaScript,同时仍然是有效的JSON。

正如@hvd在评论中指出的,空对象{}是有效的JavaScript,知道对象是空的本身可能是有价值的信息。

上述方法的比较

OWASP方式侵入性较小,因为它不需要更改客户端库,并且传输有效的JSON。然而,不确定过去或未来的浏览器错误是否能战胜这一点。正如@oriadam所指出的,目前尚不清楚数据是否会通过错误处理在解析错误中泄漏(例如window.onerror)。

谷歌的方式需要一个客户端库,以支持自动反序列化,并且可以认为在浏览器bug方面更安全。

这两种方法都需要服务器端更改,以避免开发人员意外发送易受攻击的JSON。

注意:截至2019年,导致本问题中讨论的预防措施的许多旧漏洞在现代浏览器中不再是问题。我会把下面的答案作为一个历史性的好奇,但事实上,自2010年(!!)被问及这个问题以来,整个话题已经发生了根本性的变化。


它防止它被用作简单<script>标记的目标。(好吧,这并不能阻止它,但它会让它变得不愉快。)这样,坏人就不能只将脚本标签放在自己的网站上,并依靠活动会话来获取你的内容。

编辑-记录评论(和其他答案)。问题与被破坏的内置设施有关,特别是Object和Array构造函数。可以对这些进行修改,以便在解析无害的JSON时触发攻击者代码。

它防止了JSON劫持,这是一个主要的JSON安全问题,自2011年以来,所有主要浏览器都通过ECMAScript 5正式解决了这个问题。

有争议的例子:假设谷歌有一个类似mail.Google.com/json的URL?action=inbox,以JSON格式返回收件箱的前50条消息。由于同源策略,其他域上的恶意网站无法发出AJAX请求来获取这些数据,但它们可以通过<script>标签包含URL。通过cookie访问URL,并且通过重写全局数组构造函数或访问器方法,每当设置对象(数组或哈希)属性时,都可以调用一个方法,从而允许它们读取JSON内容。

while(1);或者&&&BLAH&&&阻止了这一点:mail.google.com上的AJAX请求将完全访问文本内容,并可以将其删除。但是<script>标记插入会盲目地执行JavaScript而不进行任何处理,从而导致无限循环或语法错误。

这并不能解决跨站点请求伪造的问题。