4489

为什么谷歌会提前发送while(1);他们的(私有)JSON响应?

例如,以下是在中打开和关闭日历时的响应谷歌日历:

while(1);[[“u”[['smsSentFlag','false'],['hideInvitations','false'],['remindOnRespondEventsOnly','true'],['hideInvitations_remindOnRespondEventsOnly','false_true'],[“日历ID被剥夺隐私”,“false”],[“msVerifiedFlag”,“true”]]]]

我认为这是为了防止人们评估()但你真正需要做的是更换虽然然后你就做好了。我假设eval预防是为了确保人们编写安全的JSON解析代码。

我在其他一些地方也看到过这种用法,但在谷歌(邮件、日历、联系人等)中更是如此,谷歌文件以开头&&&开始&&&相反,谷歌联系人似乎从while(1)&&&开始&&&.

这里发生了什么?

6
  • 57
    我相信你的第一印象是正确的。如果您开始寻找代码并尝试根据源代码来调整输入流,那么您应该重新考虑并以安全的方式进行操作(因为谷歌的操作更容易)。 评论 2010年4月19日18:04
  • 48
    可能还有一个后续问题:为什么谷歌会提前发布)]}'现在,而不是while(1);? 答案会一样吗?
    – 小控件
    评论 2017年2月16日18:51
  • 7
    将阻止eval,但不会使用无限循环。 评论 2017年5月6日20:27
  • 25
    这个)]}'也可以像facebook那样节省字节用于(;;);可节省一个字节:) 评论 2017年7月8日20:55
  • 2
    为什么没有一个HTTP响应头表示“这不是Javascript;不要这样加载它”?你会认为内容类型可以解决这个问题。
    – 卡兹
    评论 2022年7月27日11:52

8个答案8

重置为默认值
4589

它可以防止JSON劫持,一个主要的JSON安全问题固定的在所有主要浏览器中自2011年起使用ECMAScript 5。

虚构的例子:假设谷歌有一个类似mail.google.com/json?action=收件箱它以JSON格式返回收件箱的前50条消息。由于同源策略,其他域上的恶意网站无法发出AJAX请求以获取此数据,但它们可以通过<脚本>标签。访问URL时使用你的饼干,以及重写全局数组构造函数或访问器方法只要设置了对象(数组或散列)属性,就可以调用它们的方法,从而允许它们读取JSON内容。

这个while(1);&&&BLAH公司&&&防止这种情况:AJAX请求位于邮箱google.com将可以完全访问文本内容,并且可以将其剥离。但是一个<脚本>标签插入盲目地执行JavaScript而不进行任何处理,从而导致无限循环或语法错误。

这并没有解决跨站点请求伪造.

8
  • 255
    为什么获取此数据的请求不需要CSRF-token呢? 评论 2013年2月3日1:43
  • 8
    返回一个包含数组的对象而不是直接返回数组,这难道不能解决问题吗? 评论 2013年2月3日18:26
  • 5
    @佩德罗·费利克斯(PedroFelix):不,这并不能解决问题,因为帖子中提到的相同攻击仍然可以执行。覆盖访问器方法以检索信息。
    – 布什利
    评论 2013年2月5日2:36
  • 204
    @雅库布。以谷歌的规模存储和维护CSRF-token需要大量的基础设施和成本。 评论 2013年2月5日5:12
  • 148
    @雅库布。反CSRF令牌会扰乱缓存,并且需要服务器端的一些加密评估。在谷歌的规模下,这将需要大量的CPU。这种方式将其卸载给客户。
    – 蓝宝石
    评论 2013年2月5日6:10
672

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

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

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

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

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

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

有多种对策:

确保JSON永远不会执行

通过放置while(1);声明之前的JSON数据,谷歌确保JSON数据永远不会作为JavaScript执行。

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

比如用于(;;);例如,在脸书上看到了同样的结果。

确保JSON不是有效的JavaScript

类似地,在JSON之前添加无效标记,如&&&开始&&&,确保从不执行。

始终返回外部带有Object的JSON

这是OWASP推荐方式以防止JSON劫持,侵入性较小。

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

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

eval('{“foo”:“bar”}')//语法错误:意外标记:

但这是有效的JSON:

JSON.parse('{“foo”:“bar”}')//对象{foo:“bar”}

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

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

上述方法的比较

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

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

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

4
  • 29
    OWASP建议很有趣,因为它很简单。有人知道谷歌的方式更安全的原因吗?
    – 葬礼
    评论 2014年3月15日1:47
  • 20
    我相信不是在任何方面都更加安全。在这里提供OWASP似乎是+1的充分理由。
    – 用户719662
    评论 2014年4月12日15:54
  • 我想如果您必须使用JSONP,您可以尝试以某种聪明(可能不安全)的方式使用CSRF令牌。 评论 2014年8月29日2:19
  • 1
    我想{}被解释为空块,而不是空对象,否则{“foo”:“bar”}(作为程序的开始)不会引发语法错误。即口译员看到{a块的开头,后跟字符串“foo”然后是冒号:标点符号放在一个意料之外的地方。如果左大括号被视为对象文字的开头,则冒号将有效。
    – 罗布·G
    评论 2022年6月12日7:39
396

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

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

0
121

这将使第三方难以将JSON响应插入带有<脚本>标签。记住<脚本>标签不受同源策略.

0
92

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


它防止它被用作简单<脚本>标签。(好吧,这并没有阻止它,但它让人不快。)这样一来,坏人就不能把脚本标签放在自己的网站上,依靠一个活跃的会话来获取你的内容。

编辑-注意评论(和其他答案)。这个问题与被破坏的内置设施有关,特别是对象阵列建造师。这些可以被更改,使得原本无害的JSON在解析时可能会触发攻击者代码。

0
16

自从<脚本>标签不受同源策略的限制,这是网络世界中的安全必要条件,而(1)添加到JSON响应时,可以防止在<脚本>标签。

12

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

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

[{“id”:“1001”,“ccnum”:“4111111111111”,“balance”:“2345.15”},{“id”:“1002”,“ccnum”:“5555555555 4444”,“余额”:“10345.00”},{“id”:“1003”,“ccnum”:“5105105105100”,“balance”:“6250.50”}]

此攻击可通过三个主要步骤实现:

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

<script src=“http://<jsonite>/json_server.php”></script>

浏览器将向发出GET请求json服务器.php并且用户的任何认证cookie将与请求一起发送。步骤3:此时,虽然恶意网站已经执行了脚本,但它无法访问任何敏感数据。使用对象原型设置器可以实现对数据的访问。在下面的代码中,当试图设置“中央控制室“属性。

对象原型__defineSetter__('ccnum',函数(obj){secrets=secrets.concat(“”,obj);});

此时,恶意网站成功劫持了敏感的财务数据(ccnum)返回通过json服务器.phpJSON格式

需要注意的是,并非所有浏览器都支持这种方法;概念验证是在Firefox 3.x上完成的。此方法现在已被弃用,并由使用对象定义属性这种攻击还有一种变体,应该在所有使用全名JavaScript(例如。pi=3.14159)返回,而不是JSON数组。

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

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

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

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

如你所见而(1)属于最后一个选项。用最简单的话来说,而(1)是一个无限循环,将一直运行到显式发出break语句。因此,将被描述为应用密钥的锁(googlebreak语句)。因此,黑客没有密钥的JSON劫持行为将被一贯驳回。唉,如果使用解析器读取JSON块,while(1)循环将被忽略。

总之而(1)循环可以更容易地可视化为简单的谷歌可以使用break语句密码来控制数据流。

然而,该语句中的关键字是“简单的'. 值得庆幸的是,多年来,已从基本实践中删除了认证无限循环的使用自2010年起由于其CPU使用量的绝对抽取孤立的(事实上,互联网已经不再通过粗暴的“快速修复”来强制执行)。如今,代码库已经嵌入了预防措施,系统不再重要或有效。(其中一部分是从JSON劫持转移到更富有成效的数据耕耘技术,我目前不会深入讨论)

身份验证到位后,JSON劫持保护可以采取形式多样。谷歌追加而(1)到JSON数据中,所以如果任何恶意脚本对其进行评估,恶意脚本将进入无限循环。

参考:网络安全测试食谱:快速发现问题的系统技术

不是你想要的答案吗?浏览标记的其他问题问你自己的问题.