它防止通过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。