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

Posted

技术标签:

【中文标题】为啥 Google 在前面加上 while(1);到他们的 JSON 响应?【英文标题】:Why does Google prepend while(1); to their JSON responses?为什么 Google 在前面加上 while(1);到他们的 JSON 响应? 【发布时间】:2010-10-26 16:04:43 【问题描述】:

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

例如,这是在Google Calendar 中打开和关闭日历时的响应:

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&&& 开头。

这是怎么回事?

【问题讨论】:

我相信你的第一印象是正确的。如果您开始寻找代码并尝试根据源修剪输入流,您会重新考虑并以安全的方式(并且由于 Google 的操作,更容易)进行。 可能是一个后续问题:为什么 google 现在要添加 )]' 而不是 while(1);?答案会一样吗? 会阻止 eval,但不是无限循环。 这个)]'也可能是为了节省字节,就像facebook使用的for(;;);节省了一个字节:) 【参考方案1】:

它可以防止 JSON hijacking,这是一个主要的 JSON 安全问题,在 ECMAScript 5 的所有主要浏览器 since 2011 中正式为 fixed。

人为的示例:假设 Google 有一个类似 mail.google.com/json?action=inbox 的 URL,它以 JSON 格式返回您收件箱的前 50 条消息。由于同源策略,其他域上的邪恶网站无法发出 AJAX 请求来获取此数据,但它们可以通过 <script> 标签包含 URL。使用 您的 cookie 访问 URL,overriding the global array constructor or accessor methods 可以在设置对象(数组或哈希)属性时调用一个方法,允许它们读取 JSON 内容。

while(1);&&&BLAH&&& 可以防止这种情况:mail.google.com 的 AJAX 请求将拥有对文本内容的完全访问权限,并且可以将其删除。但是<script>标签插入盲目地执行javascript而不做任何处理,导致死循环或语法错误。

这并没有解决cross-site request forgery 的问题。

【讨论】:

为什么获取这些数据的请求不需要 CSRF-token 来代替? 不会直接返回包含数组的对象,而不是直接返回数组,也能解决问题? @PedroFelix 不,这不能解决问题,因为仍然可以执行帖子中提到的相同攻击。覆盖访问器方法以检索信息。 @JakubP。以 Google 的规模存储和维护 CSRF 令牌需要大量的基础设施和成本。 @JakubP。反 CSRF 令牌与缓存混淆,并且需要一定数量的服务器端加密评估。在 Google 规模上,这将需要大量 CPU。这种方式将其卸载到客户端。【参考方案2】:

它可以防止通过 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。

例如,for(;;); 之类的内容已在 Facebook 上看到,结果相同。

确保 JSON 不是有效的 JavaScript

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

总是返回 JSON,外面有一个 Object

这是OWASP recommended way,用于防止 JSON 劫持,是侵入性较小的一个。

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

一个有效的 JSON 对象,当没有被任何东西包围时,在 JavaScript 中是无效的,因为 被解释为一个代码块:

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

然而这是有效的 JSON:

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

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

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

上述方法的比较

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

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

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

【讨论】:

OWASP 推荐很有趣,因为它很简单。有人知道 Google 的方式更安全的原因吗? 我相信它不是在任何方面都更安全。在这里提供 OWASP 似乎是 +1 的充分理由。 我想如果你必须使用 JSONP,你可以尝试以某种聪明(可能不安全)的方式使用 CSRF 令牌。【参考方案3】:

这是为了确保其他网站不会采取令人讨厌的伎俩来窃取您的数据。例如,通过replacing the array constructor,然后通过<script> 标签包含此JSON URL,恶意第三方站点可以从JSON 响应中窃取数据。通过在开头添加while(1);,脚本将挂起。

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

【讨论】:

【参考方案4】:

这将使第三方难以将 JSON 响应插入到带有 <script> 标签的 html 文档中。请记住,<script> 标签不受Same Origin Policy 的约束。

【讨论】:

【参考方案5】:

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


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

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

【讨论】:

【参考方案6】:

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

【讨论】:

【参考方案7】:

由于这是一篇高流量帖子,我希望在这里提供一个对原始问题稍微不确定的答案,从而提供有关 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>

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

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

至此恶意网站已经成功劫持了敏感财务数据(ccnum)返回byjson_server.php JSON

需要注意的是,并不是所有的浏览器都支持这种方式;概念验证是在 Firefox 3.x 上完成的。这种方法现在已被弃用并被 useObject.defineProperty 取代。这种攻击还有一个变体,应该适用于全名 JavaScript(例如 pi=3.14159)的所有浏览器返回而不是 JSON 数组。

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

由于 SCRIPT 标签只能生成 HTTP GET 请求,所以只返回 JSON 对象给 POST 请求。

防止网络浏览器将 JSON 对象解释为有效的 JavaScript 代码。

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

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

因此,总而言之,while(1) 循环可以更容易地可视化为 simple break 语句密码,google 可以使用它来控制数据流。

但是,该语句中的关键字是单词“simple”。值得庆幸的是,在 自 2010 年以来的几年中,已验证的无限循环的使用已从基本实践中移除,因为它在隔离时绝对减少了 CPU 使用率(以及互联网已经移动的事实远离强迫粗暴的“快速修复”)。如今,代码库已经嵌入了预防措施,系统不再重要也不再有效。 (其中一部分是从 JSON 劫持转向更有效的数据农业技术,我目前不会介绍)

​​>

【讨论】:

【参考方案8】:

身份验证到位后,JSON 劫持保护可以采取 多种形式。 Google 将 while(1) 附加到他们的 JSON 数据中,所以 如果任何恶意脚本评估它,恶意脚本进入 一个无限循环。

参考:Web Security Testing Cookbook: Systematic Techniques to Find Problems Fast

【讨论】:

以上是关于为啥 Google 在前面加上 while(1);到他们的 JSON 响应?的主要内容,如果未能解决你的问题,请参考以下文章

为啥调用css在前面加上反斜杠<link href="/template/images/style.css" >

java里为啥主函数前面要加static修饰

为啥C#中数据库sql语句中在表的前面加上.dbo,不加也能正常执行,两者有啥区别!

如何使用GOOGLE,越详细越好

为啥这个while循环在Python中永远不会停止

为啥javascript不会在while循环中堆叠