为什么 Google 在前面加上 while(1);到他们的 JSON 响应?

Why does Google prepend while(1); to their JSON responses?

提问人:Jess 提问时间:4/20/2010 最后编辑:Mickael LherminezJess 更新时间:12/7/2022 访问量:598965

问:

为什么 Google 会在他们的(私有)JSON 响应之前添加?while(1);

例如,以下是在 Google 日历中开启和关闭日历时的响应:

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

我认为这是为了防止人们在上面做一个,但你真正要做的就是替换它,然后你就被设置好了。我认为评估预防是确保人们编写安全的 JSON 解析代码。eval()while

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

这是怎么回事?

JavaScript JSON AJAX 安全性

评论

57赞 Esteban Küber 4/20/2010
我相信你的第一印象是正确的。如果你开始寻找代码并尝试根据源修剪输入流,你会重新考虑并以安全(并且由于 Google 的行动,更容易)的方式进行。
47赞 Gizmo 2/17/2017
可能是一个后续问题:为什么谷歌现在预置而不是?答案会是一样的吗?)]}'while(1);
7赞 Mardoxx 5/7/2017
会阻止 eval,但不会无限循环。
24赞 Gras Double 7/9/2017
这也可能是为了节省字节,比如 facebook 使用,它:)保存一个字节)]}'for(;;);
1赞 Kaz 7/27/2022
为什么没有一个HTTP响应头,上面写着“这不是Javascript;不要这样加载它“?你会认为内容类型会处理它。

答:

396赞 bdonlan 5/16/2009 #1

这是为了确保其他一些网站不能做令人讨厌的伎俩来试图窃取您的数据。例如,通过替换数组构造函数,然后通过标记包含此 JSON URL,恶意第三方站点可以从 JSON 响应中窃取数据。通过在开头放置 a,脚本将挂起。<script>while(1);

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

92赞 Pointy 4/20/2010 #2

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


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

编辑 — 记下评论(和其他答案)。这个问题与被颠覆的内置设施有关,特别是 和 构造函数。这些可以被更改,以便原本无害的 JSON 在解析时可以触发攻击者代码。ObjectArray

121赞 Daniel Vassallo 4/20/2010 #3

这将使第三方难以将 JSON 响应插入到带有标记的 HTML 文档中。请记住,该标签不受同源策略的约束。<script><script>

4582赞 rjh 4/20/2010 #4

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

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

OR 可以防止这种情况发生:AJAX 请求将具有对文本内容的完全访问权限,并且可以将其剥离。但是,标签插入会在没有任何处理的情况下盲目地执行 JavaScript,从而导致无限循环或语法错误。while(1);&&&BLAH&&&mail.google.com<script>

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

评论

254赞 Jakub P. 2/3/2013
为什么获取此数据的请求不需要 CSRF 令牌?
7赞 Pedro Felix 2/4/2013
返回包含数组的对象,而不是直接返回数组,难道不也能解决问题吗?
5赞 Boushley 2/5/2013
@PedroFelix 不,这并不能解决问题,因为仍然可以执行帖子中提到的相同攻击。重写访问器方法以检索信息。
204赞 abraham 2/5/2013
@JakubP。以 Google 的规模存储和维护 CSRF 令牌需要大量的基础设施和成本。
148赞 bluesmoon 2/5/2013
@JakubP。反 CSRF 令牌会扰乱缓存,并且需要在服务器端进行一定数量的加密评估。在谷歌的规模下,这将需要大量的CPU。这种方式将其卸载到客户端。
672赞 Arnaud Le Blanc 2/2/2014 #5

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

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

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

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

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

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

有多种对策:

确保 JSON 永远不会执行

通过在 JSON 数据之前放置语句,Google 可以确保 JSON 数据永远不会作为 JavaScript 执行。while(1);

只有合法的页面才能真正获取全部内容,剥离 ,并将其余部分解析为 JSON。while(1);

例如,在Facebook上看到过类似的东西,结果相同。for(;;);

确保 JSON 不是有效的 JavaScript

同样,在 JSON 之前添加无效的标记(如 )可确保它永远不会被执行。&&&START&&&

始终返回 JSON 并在外部使用 Object

这是 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)在解析错误中泄露。

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

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

评论

28赞 funroll 3/15/2014
OWASP建议很有趣,因为它很简单。有人知道谷歌的方式更安全的原因吗?
19赞 4/12/2014
我相信它在任何方面都没有更安全。在这里提供 OWASP 似乎是 +1 的充分理由。
0赞 Kelsey Francis 8/29/2014
我想如果你必须使用JSONP,你可以尝试以某种聪明的(可能是不安全的)方式使用CSRF令牌。
1赞 RobG 6/12/2022
我认为被解释为一个空块,而不是一个空对象,否则(作为程序的开始)不会抛出语法错误。也就是说,解释器看到 a 是块的开头,然后是字符串,然后是冒号标点符号,位于意想不到的位置。如果左大括号被视为对象文字的开头,则冒号将有效。{}{"foo":"bar"}{"foo":
16赞 Krishna Ganeriwal 8/18/2017 #6

由于该标签不受同源策略的约束,而同源策略在 Web 世界中是安全必需的,因此当添加到 JSON 响应中时,可以防止在标签中滥用它。<script>while(1)<script>

3赞 JSON C11 3/2/2020 #7

身份验证到位后,JSON 劫持保护可以采取 形式多样。Google 将 while(1) 附加到他们的 JSON 数据中,因此 如果任何恶意脚本对其进行评估,则恶意脚本会进入 无限循环。

参考资料:《Web Security Testing Cookbook: Systematic Techniques to Finding Problems

12赞 Montresor 12/24/2020 #8

由于这是一篇高流量的帖子,我希望在这里提供一个对原始问题稍有不确定性的答案,从而提供有关 JSON 劫持攻击及其后果的进一步背景

顾名思义,JSON 劫持是一种类似于跨站点请求伪造的攻击,攻击者可以从应用程序访问跨域敏感 JSON 数据,这些应用程序将敏感数据作为数组文本返回给 GET 请求。返回数组文本的 JSON 调用示例如下所示:

[{"id":"1001","ccnum":"4111111111111111","balance":"2345.15"}, 
{"id":"1002","ccnum":"5555555555554444","balance":"10345.00"}, 
{"id":"1003","ccnum":"5105105105105100","balance":"6250.50"}]

这种攻击可以通过 3 个主要步骤实现:

第 1 步:让经过身份验证的用户访问恶意页面。 第 2 步:恶意页面将尝试从用户登录的应用程序访问敏感数据。这可以通过在 HTML 页面中嵌入脚本标记来完成,因为同源策略不适用于脚本标记。

<script src="http://<jsonsite>/json_server.php"></script>

浏览器将向 GET 发出请求,用户的任何身份验证 cookie 将与请求一起发送。 步骤3: 此时,虽然恶意站点已执行脚本,但它无权访问任何敏感数据。通过使用对象原型设置器,可以实现对数据的访问。在下面的代码中,当尝试设置 “” 属性时,对象 prototypes 属性将绑定到定义的函数。json_server.phpccnum

Object.prototype.__defineSetter__('ccnum',function(obj){
    secrets =secrets.concat(" ", obj);
});

此时,恶意站点已成功劫持返回的敏感财务数据 JSON(ccnum)byjson_server.php

需要注意的是,并非所有浏览器都支持此方法;这个方法现在已被弃用,取而代之的是 这种攻击还有一种变体,应该适用于所有返回全名 JavaScript (例如 ) 而不是 JSON 数组的浏览器。useObject.definePropertypi=3.14159

有几种方法可以防止 JSON 劫持:

  • 由于 SCRIPT 标签只能生成 HTTP GET 请求,因此它们只能将 JSON 对象返回给 POST 请求。

  • 阻止 Web 浏览器将 JSON 对象解释为有效的 JavaScript 代码。

  • 通过要求所有 JSON 请求都需要预定义的随机值来实现跨站点请求伪造保护。

所以正如你所看到的,属于最后一个选项。用最简单的术语来说,是一个无限循环,它将一直运行到显式发出 break 语句。因此,将被描述为要应用的密钥的锁(google break 语句)。因此,黑客没有密钥的 JSON 劫持将始终被驳回。唉,如果您使用解析器读取 JSON 块,则会忽略 while(1) 循环。While(1)while(1)

因此,总而言之,该循环可以更容易地可视化为一个简单的中断语句密码,谷歌可以使用它来控制数据流。while(1)

但是,该声明中的关键字是“简单”一词。值得庆幸的是,自 2010 年以来的几年里,经过身份验证的无限循环的使用已经从基本实践中删除,因为它在隔离时绝对会降低 CPU 使用率(而且互联网已经不再强制通过粗略的“快速修复”)。如今,代码库已经嵌入了预防措施,系统不再重要或有效。(其中一部分是从 JSON 劫持转向更有成效的数据耕作技术,我目前不会讨论)