ChatGPT解决这个技术问题 Extra ChatGPT

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

为什么 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(;;); 节省一个字节 :)

P
PaulMest

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

人为的示例:假设 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 令牌?
不返回包含数组的对象,而不是直接返回数组,也能解决问题吗?
@PedroFelix 不,这不能解决问题,因为仍然可以执行帖子中提到的相同攻击。覆盖访问器方法以检索信息。
@JakubP。以 Google 的规模存储和维护 CSRF 令牌需要大量的基础设施和成本。
@JakubP。反 CSRF 令牌与缓存混淆,并且需要一定数量的服务器端加密评估。在 Google 规模上,这将需要大量 CPU。这种将其卸载到客户端。
r
ruohola

它可以防止通过 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 与外部的 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 在评论中所指出的,空对象 {} 是有效的 JavaScript,知道对象为空本身可能是有价值的信息。

上述方法的比较

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

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

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


OWASP 推荐很有趣,因为它很简单。有人知道谷歌的方式更安全的原因吗?
我相信它不会以任何方式更安全。在这里提供 OWASP 似乎是 +1 的充分理由。
我想如果你必须使用 JSONP,你可以尝试以某种聪明(可能不安全)的方式使用 CSRF 令牌。
我认为 {} 被解释为一个空块,而不是一个空对象,否则 {"foo":"bar"} (作为程序的开始)不会引发语法错误。即解释器看到 { 是一个块的开头,后跟字符串 "foo" 后跟冒号 : 标点符号在一个它不期望的地方。如果左大括号被视为对象文字的开始,那么冒号将是有效的。
h
hippietrail

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

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


G
George Stocker

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


P
Pointy

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

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

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


P
Pang

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


n
np_6

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

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

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

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

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

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


J
JSON C11

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

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