可能的重复: 为什么人们会写“throw 1;<不要邪恶>”和“for(;;);”在json响应前?

我发现这种语法在Facebook上用于Ajax调用。for (;;);部分在回应的开始。它的用途是什么?

这是调用和响应:

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

回应:

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

当前回答

I suspect the primary reason it's there is control. It forces you to retrieve the data via Ajax, not via JSON-P or similar (which uses script tags, and so would fail because that for loop is infinite), and thus ensures that the Same Origin Policy kicks in. This lets them control what documents can issue calls to the API — specifically, only documents that have the same origin as that API call, or ones that Facebook specifically grants access to via CORS (on browsers that support CORS). So you have to request the data via a mechanism where the browser will enforce the SOP, and you have to know about that preface and remove it before deserializing the data.

所以,是的,这是关于控制(有用的)访问数据。

其他回答

我来晚了一点,tj基本上已经解开了这个谜团,但我想我应该分享一篇关于这个特定主题的好论文,其中有很好的例子,并对这个机制提供了更深入的见解。

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

这个想法很简单,也很漂亮:许多用户倾向于永久登录Gmail或Facebook。所以你要做的就是建立一个网站,在恶意网站的Javascript中重写对象或数组构造函数:

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

然后在该站点中包含一个<script>标记,例如

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

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

如承诺的,论文链接。

这看起来像是一个防止CSRF攻击的黑客。有特定于浏览器的方法来挂钩到对象创建,所以恶意网站可以先这样做,然后有以下:

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

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

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

Well the for(;;);是一个无限循环(如果你想的话,你可以使用Chrome的JavaScript控制台在一个选项卡中运行该代码,然后在任务管理器中观察cpu的使用情况,直到浏览器杀死该选项卡)。

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

为了进一步解释,使用JavaScript的eval()函数解析一些json格式的数据是相当常见的,例如:

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

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

正因为如此,使用eval()这样的东西来解析json格式的数据通常是不受欢迎的,而for(;;);语句将阻止人们以这种方式解析数据。任何尝试的人都会得到一个无限循环。所以从本质上讲,这就像Facebook试图强制人们使用其API,以一种不会让他们容易受到未来试图劫持Facebook API作为载体的攻击的方式。

I suspect the primary reason it's there is control. It forces you to retrieve the data via Ajax, not via JSON-P or similar (which uses script tags, and so would fail because that for loop is infinite), and thus ensures that the Same Origin Policy kicks in. This lets them control what documents can issue calls to the API — specifically, only documents that have the same origin as that API call, or ones that Facebook specifically grants access to via CORS (on browsers that support CORS). So you have to request the data via a mechanism where the browser will enforce the SOP, and you have to know about that preface and remove it before deserializing the data.

所以,是的,这是关于控制(有用的)访问数据。

Facebook has a ton of developers working internally on a lot of projects, and it is very common for someone to make a minor mistake; whether it be something as simple and serious as failing to escape data inserted into an HTML or SQL template or something as intricate and subtle as using eval (sometimes inefficient and arguably insecure) or JSON.parse (a compliant but not universally implemented extension) instead of a "known good" JSON decoder, it is important to figure out ways to easily enforce best practices on this developer population.

为了应对这一挑战,Facebook最近一直在“全力”开发内部项目,旨在优雅地执行这些最佳实践,老实说,对于这种特定情况,真正有意义的唯一解释只是:有人内部决定,所有JSON解析都应该通过其核心库中的单个实现,而强制执行的最佳方法是对每个API响应进行get for(;;);自动钉在前面。

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

所提供的其他答案似乎都分为两类:

误解JSONP,或者 误解“JSON劫持”。

第一类依赖于攻击者可以“使用JSONP”向不支持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(;;);prefix trick只是“偶然”出现在这个例子中,实际上是由其他返回数组的Facebook内部api返回的;但在这种情况下,确实应该注意到这一点,因为这将是为什么(;;);出现在这个特定的片段中。