Author: Zeng Peisen

| guide language In fact in the front-end coding, more or less will be in contact with the sandbox, probably naive good you didn’t notice, and may, you still don’t know the real purpose of it, learn to use the sandbox, can avoid potential code injection and unknown security problems.

preface

A sandbox, as the name suggests, allows your programs to run in an isolated environment, with no impact on other programs outside of it. By creating a separate environment like a sandbox, programs running inside the sandbox cannot permanently affect the hard disk.

To take a simple example, each TAB in our browser, Chrome, is a sandbox. The renderer process is sandboxed, and the web code content of the web page must pass through the IPC channel to communicate with the browser kernel process, which is checked for security. The purpose of the sandbox is to keep untrusted code running in an environment that limits its access to resources outside the quarantine.

Usage scenario of sandbox in JS

There will also be sandbox applications in front-end JS, after all sometimes you need to fetch third-party JS files or data? When the data is not reliable, it is particularly important to create a sandbox and do a good job of insurance.

1. Jsonp: When parsing the JSONP request returned by the server, if you do not trust the data in JSONP, you can create a sandbox to parse and obtain the data; (When jSONP requests are processed in TSW, sandboxes are created to process and parse the data);

2. Execute third-party JS: when you need to execute third-party JS, and the JS file is not reliable;

3, online code editor: I believe that you have used some online code editors, and the execution of these codes, basically placed in the sandbox, to prevent the impact on the page itself; (e.g., https://codesandbox.io/s/new)

4. Vue server rendering: In the implementation of Vue server rendering, the bundle file of the front end is executed by creating a sandbox; When the createBundleRenderer method is called, it is possible to configure runInNewContext as true or false to determine whether a newly created Sandbox object is passed in for use by the VM.

5. Expression evaluation in the VUE template: Expression evaluation in the VUE template is sandboxed and can only access a whitelist of global variables, such as Math and Date. You cannot attempt to access user-defined global variables in template expressions.

In summary: The sandbox comes in handy when you parse or execute untrusted JS, when you isolate the execution environment of the code being executed, and when you restrict the accessible objects in the executing code.

With + new Function

Let’s start with the simplest approach. If you want to execute a piece of code directly through eval and function, it’s not realistic. You can go up the scope chain inside the code and tamper with global variables, which we don’t want. However, you can use the with API. Under the block-level scope of with, variable access looks first for the parameter object you pass in and then up, so you’re monitoring “variable access” in your code:

The next thing you need to do is expose the variable exposeObj that can be accessed and block external access from inside the sandbox. With the proxy feature provided by ES6, you can get all the overwrites on the object:

By setting the HAS function, you can listen for variable access. In the above code, only a few external variables are exposed for the code to access. The rest of the attributes that do not exist are directly raised with an error. There are also get and set functions, but if get and set only intercept operations on the current object property, read and write operations on external variable properties cannot be listened on, so use has instead. Let’s test it out:

When console.log(a.b) is called, the has method cannot listen for access to the b property, assuming that the code being executed is untrusted. It only needs A.B. __proto__ to access the Object constructor’s prototype Object and tamper with it, such as toString, to affect the external code logic.


For example, the code shown above realizes sandbox escape by accessing the prototype chain and tampering with the toString method on the prototype chain. Once the external code executes the toString method, it can implement XSS attacks and inject third-party code. To bypass the scoped chain lookup, I get the constructor Function by accessing the constructor of the arrow Function. At this point, the XSS code executed within the Funtion is executed at the time of execution. Instead of going up the scope chain, it executes directly under the global scope, which enables sandbox escape and XSS attacks.

You might wonder, if I cut off access to the prototype chain, would that stop it? True, you can pass in an Object with no prototype chain by object.create (null), exposing only one layer of objects, and passing no nested objects, but even primitive values, numbers, or strings can find the prototype chain by __proto__, and even without passing an Object, You can also get around this by:

New Function + with is a sandbox for code analysis and filtering. If the incoming code is not in a specified data format (such as JSON), it is always not safe to throw an error to prevent malicious code injection.

Sandbox implementation two: Implement sandbox with iframe

Described above a inferior, not very safe method constructs a simple sandbox, but in front of the most common method, or use the iframe to construct a sandbox, to as online code editor: https://codesandbox.io/s/news.

This way is more convenient, simple and safe, and is also the more common front-end sandbox implementation scheme at present. If the code you want to execute is not your own code, not a trusted data source, then you must use the IFrame sandbox. Sandbox is a new attribute in H5, enabled by using the sandbox attribute in the iframe tag:

But there are some limitations:

Script script cannot be executed 2. Ajax request cannot be sent 3. Do not use localStorage, such as localStorage and cookies. 4. Can’t create new popovers and Windows 5. Can’t send forms 6. Can’t load extra plug-ins like Flash etc

However, you can configure the iframe tag in a few ways:

Then you just need to use the postMessage API to pass in the code you need to execute, the data you need to expose, and communicate with your iframe page.

1) However, you should be careful not to let the executing code access the contentWindow object in the child page, because you need to call the contentWindow postMessageAPI to pass information to the parent page. If the malicious code also gets the contentWindow object, You get control of the parent page, which is not good.

2) When using the postMessageAPI, allow-same-Origin is set to allow two pages to communicate with each other, which means that sub-pages can initiate requests. At this time, you need to protect against CSRF and allow same-domain requests. Fortunately, they didn’t carry a cookie.

3) when you call the postMessageAPI to pass data to a child page, the data object itself has already been copied by structured cloning algorithm, check this out if you are not familiar with structured cloning algorithm.

In short, objects passed through the postMessageAPI have already been processed by the browser, the prototype chain has been broken, and the objects that are passed have also been copied in different memory space, so you don’t have to worry about sandbox problems.

Sandbox usage in NodeJS

Using the sandbox in NodeJS is very simple, just using the native VM module, you can quickly create the sandbox and specify the context.

The vm provides three methods: runInNewContext, runInThisContext, and runInContext. There are some differences in the usage of the three methods. The runInNewContext and runInContext are commonly used.

But is the VM completely secure? Not necessarily.

Using this code, we can stop the main nodeJS process from executing on the VM, which we don’t want to do. The solution is to bind the context objects and avoid escaping through the prototype chain. So we need to break the prototype chain and supply only the primitive type values for the incoming exposed object.

Let’s look at how TSW is used:

RunInNewContext returns the constructor Function in the sandbox, passing in an empty object that breaks the prototype chain to prevent escape. When used externally, you simply call the returned Function, just like normal new Function.

Even so, we can’t guarantee absolute security, after all, could there be a potential sandbox vulnerability?

conclusion

Even if we know how to use the sandbox during development to keep our execution environment from being affected, the sandbox is not always completely safe, and every year there are so many hackers who are trying to figure out how to get out of the browser sandbox and nodeJS sandbox, so my personal advice is:

1. Do not execute untrusted third-party JS on the business code. If it is necessary to execute third-party JS, you can maintain the whitelist by setting CSP;

2. Do not trust any user data source to prevent malicious users from injecting code.

Out of curiosity, I sorted out this article, and hope to correct any mistakes.

Pay attention to [IVWEB community] public number to get the latest weekly articles, leading to the top of life!