【问题标题】:What does a Ajax call response like 'for (;;); { json data }' mean? [duplicate]像'for (;;); 这样的 Ajax 调用响应是什么? { json 数据 }' 是什么意思? [复制]
【发布时间】:2011-09-14 10:48:57
【问题描述】:

可能重复:
Why do people put code like “throw 1; <dont be evil>” and “for(;;);” in front of json responses?

我发现这种语法在 Facebook 上用于 Ajax 调用。我对回复开头的for (;;); 部分感到困惑。它是干什么用的?

这是调用和响应:

GET http://0.131.channel.facebook.com/x/1476579705/51033089/false/p_1524926084=0

回复:

for (;;);{"t":"continue"}

【问题讨论】:

  • 有趣的问题。我想知道他们如何解释数据。只需摆脱for(;;); 并解析结果?
  • 我不会与骗子合并,因为虽然他们是关于同一主题的,但这个问题的答案不会那么好。
  • 我真的很沮丧,因为投票最多的三个答案是错误的。然而,这是重复的问题有正确的答案。这是简单明了地传播错误信息。这更令人沮丧,因为 saurik 非常有名,而另外两个拥有成千上万的声誉。

标签: ajax json facebook


【解决方案1】:

我怀疑它存在的主要原因是控制。它强制您通过 Ajax 检索数据,而不是通过 JSON-P 或类似方式(使用 script 标签,因此会失败,因为 for 循环是无限的),从而确保Same Origin Policy 启动。这让他们可以控制哪些文档可以发出对 API 的调用——具体来说,只有与该 API 调用具有相同来源的文档,或者 Facebook 通过CORS 专门授予访问权限的文档(在浏览器上支持 CORS)。因此,您必须通过浏览器强制执行 SOP 的机制来请求数据,并且您必须了解该前言并在反序列化数据之前将其删除。

是的,它是关于控制(有用的)对数据的访问。

【讨论】:

  • 感谢您回答 T.J Crowder。我不清楚是否需要击败反序列化尝试,它对安全性有何帮助以及它可以防止什么样的攻击?
  • @mridkash:我唯一能想到的是他们不希望人们通过 JSON-P 使用该 API,它使用 script 标签来绕过同源策略。此外,他们显然只希望知道for 循环的人使用结果,因为这当然会破坏任何标准的JSON 解码器(如果解码器依赖于eval,则以一种非常卑鄙的方式)。因此,除非通过 ajax 和知道删除该前言的人检索,否则该 API 是无用的。也许它只供他们的客户端代码使用,并且他们会定期更改标记...
  • @mridkash:是的,但请记住,它只控制通过网络浏览器滥用数据。任何想要手动获取数据的人,或使用非基于浏览器的工具来检索文本并在自动化过程中使用它(甚至创建一个去除前缀的反射器)。所以它并不像它真的很安全,只是让人们感到尴尬。反射器最终会作为显着活跃的客户端出现在您的日志中。 :-)
  • 为什么不用/*作为前缀呢?
  • @Crowder:在较旧的浏览器中,可以覆盖 Array() 函数,以便捕获传递的数据。这意味着您不能总是假设在脚本标签中评估的 JSON 文字不会泄漏。
【解决方案2】:

for(;;); 是一个无限循环(如果需要,您可以使用 Chrome 的 JavaScript 控制台在选项卡中运行该代码,然后观察任务管理器中的 CPU 使用率飙升,直到浏览器杀死标签)。

所以我怀疑它可能被放在那里是为了挫败任何试图使用 eval 或任何其他执行返回数据的技术来解析响应的人。

为了进一步解释,过去使用 JavaScript 的 eval() 函数解析一些 JSON 格式的数据是相当普遍的,通过执行以下操作:

var parsedJson = eval('(' + jsonString + ')');

...这被认为是不安全的,但是,好像由于某种原因,您的 JSON 格式的数据包含可执行的 JavaScript 代码而不是(或除了)JSON 格式的数据,那么该代码将由 eval() 执行.这意味着如果您正在与不受信任的服务器交谈,或者如果有人破坏了受信任的服务器,那么他们可以在您的页面上运行任意代码。

因此,使用 eval() 之类的东西来解析 JSON 格式的数据通常是不受欢迎的,Facebook JSON 中的 for(;;); 语句会阻止人们以这种方式解析数据。任何尝试的人都会陷入无限循环。因此,从本质上讲,这就像 Facebook 试图强制人们以一种不会让他们容易受到未来试图劫持 Facebook API 以用作向量的攻击的方式使用其 API。

【讨论】:

  • 感谢您的回答。所以这意味着它是出于安全目的吗?但是,我不清楚它应该击败什么样的安全黑客。
  • @mridkash - 我在答案中添加了一些内容,希望对您能更好地解释一些事情。
  • 但是JSON.parse('for (;;);{"t":"continue"}')会中断(SyntaxError),这是在Javascript中解析Json的安全方式。
  • 但是,eval('for (;;);{"t":"continue"}'.substring(9)) 不是那么容易吗?
  • @aero - 请准确解释您认为它有什么问题。 for(;;); 实际上是一个无限循环。如果您没有预料到这一点并且您尝试eval() 它,那么您的eval() 将永远不会返回。这可以作为一个站点范围的策略来制定,以防止内部开发人员不小心使用eval() 来解析异步 API 调用的结果。无论如何,这两个答案都包含有效点和不同点。这不是一个完全正确,而其他所有错误的情况。
【解决方案3】:

这看起来像是防止 CSRF 攻击的 hack。有一些特定于浏览器的方法可以挂钩对象创建,因此恶意网站可以先使用此方法,然后再进行以下操作:

<script src="http://0.131.channel.facebook.com/x/1476579705/51033089/false/p_1524926084=0" />

如果在 JSON 之前没有无限循环,则会创建一个对象,因为 JSON 可以eval()ed 作为 javascript,并且钩子会检测到它并嗅探对象成员.

现在,如果您从浏览器访问该网站,同时登录 Facebook,它可以像您一样获取您的数据,然后通过 AJAX 或 javascript 帖子等方式将其发送回自己的服务器。

【讨论】:

  • 任何关于挂钩到对象创建的示例或链接?用 Google 快速搜索找不到任何东西。
  • @dave1010 在大多数浏览器中,能够挂钩 array 创建是一个已知的安全问题。然而,对象没有这样的问题。这就是为什么在 JSON 中返回数组时常见的反 CSRF 技术是将数组包装在另一个对象中。
  • @Alan,是的,我知道将Array 重新定义为获取已创建数组的函数。由于没有办法对对象执行此操作,实际上是否需要 for(;;); 前缀?
  • @dave1010 数组文字是有效的 JSON。强制每个人使用 CSRF 保护要比希望构建 JSON 响应的人知道顶级数组是 CSRF 漏洞要明显得多,也不容易出错。
  • @Clueless 说得好。我猜for(;;); 不是必需的,如果您确定自己知道自己在做什么并且将始终控制 JSON 格式。
【解决方案4】:

我来晚了,T.J.基本上解开了这个谜团,但我想我会分享一篇关于这个特定主题的精彩论文,其中有很好的例子,并提供了对该机制的更深入了解。

这些无限循环是针对“Javascript 劫持”的一种对策,这种攻击因Jeremiah Grossman 发布的针对 Gmail 的攻击而引起了公众的关注。

这个想法既简单又美观:许多用户倾向于在 Gmail 或 Facebook 中永久登录。所以你要做的是建立一个站点,然后在你的恶意站点的 Javascript 中覆盖对象或数组构造函数:

function Object() {
    //Make an Ajax request to your malicious site exposing the object data
}

然后您在该站点中包含&lt;script&gt; 标记,例如

<script src="http://www.example.com/object.json"></script>

最后,您可以阅读恶意服务器日志中有关 JSON 对象的所有信息。

如承诺的那样,paper 的链接。

【讨论】:

    【解决方案5】:

    Facebook 有大量的开发人员在内部从事许多项目,而且有人犯小错误是很常见的;无论是像未能转义插入 HTML 或 SQL 模板的数据这样简单和严重的事情,还是像使用 eval(有时效率低下且可能不安全)或 JSON.parse(一个合规但未普遍实现的扩展)这样复杂和微妙的事情) 而不是“已知良好”的 JSON 解码器,重要的是要找出在此开发人员群体中轻松实施最佳实践的方法。

    为了应对这一挑战,Facebook 最近一直在“全力以赴”开展旨在优雅地执行这些最佳实践的内部项目,老实说,对这个特定案例真正有意义的唯一解释就是:有人在内部决定所有 JSON 解析都应通过其核心库中的单个实现,并且执行此操作的最佳方法是让每个 API 响应自动将 for(;;); 标记在前面。

    这样做,开发人员不能“懒惰”:如果他们使用eval(),他们会立即注意到,想知道发生了什么,然后意识到他们的错误并使用批准的 JSON API。

    提供的其他答案似乎都属于以下两类之一:

    1. 误解了 JSONP,或者
    2. 对“JSON 劫持”的误解。

    第一类的人相信攻击者可以以某种方式“使用 JSONP”向不支持它的 API 发出请求。 JSONP 是服务器和客户端都必须支持的协议:它要求服务器返回类似于myFunction({"t":"continue"}) 的内容,以便将结果传递给本地函数。您不能只是偶然“使用 JSONP”。

    第二类的人引用了一个非常真实的漏洞,该漏洞已被描述为允许通过标签对使用 JSONP(例如这个)的 API 进行跨站点请求伪造,从而允许“JSON 劫持”的形式。这是通过更改 Array/Object 构造函数来完成的,它允许访问从服务器返回的信息而无需包装函数。

    但是,这在这种情况下根本不可能:它之所以能工作,是因为一个裸数组(许多 JSON API 的一个可能结果,例如著名的 Gmail 示例)是一个有效的表达式语句,它不是对一个裸对象来说是正确的。

    事实上,JSON 定义的对象的语法(包括字段名称的引号,如本例所示)与块的语法冲突,因此不能在脚本的顶层使用。

    js> {"t":"continue"}
    typein:2: SyntaxError: invalid label:
    typein:2: {"t":"continue"}
    typein:2: ....^
    

    要通过 Object() 构造函数重新映射来利用此示例,它需要 API 在一组括号内返回对象,使其成为有效的 JavaScript(但不是有效的 JSON)。

    js> ({"t":"continue"})
    [object Object]
    

    现在,可能这个for(;;);前缀技巧只是“偶然”出现在这个例子中,实际上是由其他返回数组的内部Facebook API返回的;但在这种情况下,确实应该注意这一点,因为那将是for(;;); 出现在这个特定的 sn-p 中的“真正”原因。

    【讨论】:

    • 这应该被标记为正确答案。 “for(;;);”前缀很可能是作为修复 Array 构造函数重映射漏洞的副产品添加的。
    • for(;;); 被用来禁止eval 是没有意义的。 Facebook 有更好的方法来控制自己的代码。 for(;;); 也同样破坏了所有 JSON 解析器,包括 eval。在任何情况下,开发人员都必须手动删除它,但这几乎不会阻止eval。答案是 JSON 劫持尝试。是的,单独的对象字面量是无效的,但是在所有 JSON 前面插入(然后删除)for(;;) 比使用条件语句更容易且不易出错。
    猜你喜欢
    • 2013-09-26
    • 1970-01-01
    • 2015-03-12
    • 2014-02-18
    • 2017-10-25
    • 1970-01-01
    相关资源
    最近更新 更多