Facebook 有大量的开发人员在内部从事许多项目,而且有人犯小错误是很常见的;无论是像未能转义插入 HTML 或 SQL 模板的数据这样简单和严重的事情,还是像使用 eval(有时效率低下且可能不安全)或 JSON.parse(一个合规但未普遍实现的扩展)这样复杂和微妙的事情) 而不是“已知良好”的 JSON 解码器,重要的是要找出在此开发人员群体中轻松实施最佳实践的方法。
为了应对这一挑战,Facebook 最近一直在“全力以赴”开展旨在优雅地执行这些最佳实践的内部项目,老实说,对这个特定案例真正有意义的唯一解释就是:有人在内部决定所有 JSON 解析都应通过其核心库中的单个实现,并且执行此操作的最佳方法是让每个 API 响应自动将 for(;;); 标记在前面。
这样做,开发人员不能“懒惰”:如果他们使用eval(),他们会立即注意到,想知道发生了什么,然后意识到他们的错误并使用批准的 JSON API。
提供的其他答案似乎都属于以下两类之一:
- 误解了 JSONP,或者
- 对“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 中的“真正”原因。