WebApp Sandboxing & Challenges of Executing User's Code
Published: 2021-08-20 22:21:16

I've recently wanted to create a web app(in javascript) that has an online code editor and executes a user's code. I expected the code editor implementation to be a simple task. And that I could use the `eval()` JS function to evaluate the user's code. But I soon found out that there is a significant security flaw to this approach. So in this blog, I will go over some security challenges you need to think about when executing a user's code. 

## Preventing your app from crashing

Sandboxing is an excellent way to prevent your app from crashing and provide better security. Sandboxing refers to creating two separate environments, one for executing untested code and another for your production environment(your app). Failing to isolate the two environments will likely crash your app when the user's code throws an error. Or when the user manipulates the DOM in a way that is not intended.

Want to see how DOM manipulation could render your app useless? Visit any site on your browse and run the code below in the browser's developer tools console.

```javascript
document.querySelector('body').innerHTML = ''
```

![Screen Shot 2021-08-20 at 2.02.56 PM](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4eg9tr99aptcxuv12szm.png)


If you executed the code above, your browser's window would be blank, similar to the image above.

## Avoid sharing malicious code

When it comes to security, you need to be careful if you plan on letting users share code similar to the CodePen site. The main concern with code sharing is that other users may accidentally run malicious code and expose sensitive data.

Want to see how easy it is to expose sensitive information on the browser? For our next example, I will visit Facebook's homepage and run the code below in the console. The code will add an event listener to all the inputs and extracts the value.

```javascript
const inputs = document.querySelectorAll('input')
const logInputValue = (e) => console.log(e.target.value)
inputs.forEach(input => input.addEventListener('change', logInputValue))
```
![Screen Shot 2021-08-20 at 11.29.19 AM](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t0qcarigwyj1cvh5zavz.png)

Even though the code logs the login credentials to the console, a malicious user can instead send the login credentials to themselves, thus making the account vulnerable. Not only are we able to access input values, but there are also vulnerabilities you should be aware of, such as allowing access to local storage.


## A simple solution to sandboxing

There are a couple of ways of creating a sandboxed environment. A common way that most online editors create a sandboxed environment is by running multiple servers. One server will run the app, and another will receive, bundle, and send back the code preview.

Luckily, you could also achieve similar results using the `iframe` HTML element. If you would like to follow along, open your favorite code editor and create a new `index.html` file. Then add the code below into your HTML file.

```html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>

</head>
  <body>
    <iframe sandbox="allow-scripts"  srcdoc="
      <html> 
        <body>
          <textarea></textarea>
          <button id='submit-btn'>Submit</button>

        </body>
      </html>">

    </iframe>
  </body>
</html>
```
Now let's go over the two attributes we've provided to our iframe element. The `sandbox` attribute adds multiple restrictions to the `iframe` element. By default, all restrictions will apply to the `iframe` if you provide an empty string to the `sandbox` attribute. And any value token provided to `sandbox` will lift the particular restriction. In this case, we just want to run javascript code, so we'll provide `allow-scripts` as a value to the `sandbox` attribute.

The `srcdoc` attribute is straightforward. Instead of providing an external link to the `iframe` content. We use `srcdoc` to provide the content directly to our iframe HTML element.

### How can we confirm that both environments have restricted access?

Want to make sure that your `iframe` element has restricted access? Follow the steps below. Please note that I will be using google chrome as my browser for this demo.

1. Open the `index.html` file in your browser running a live server. If you are using VSCode, you can right-click on the HTML file and select `Open with Live Server`
2. Open the developer tools; Option + ⌘ + J (on macOS), or Shift + CTRL + J (on Windows/Linux).
3.Navigate to the `Console` tab.
4. If you run the `localStorage` command in the console, you will get information about your local storage.
5. Now select your `iframe` element in the `Javascript Context` dropdown and run the `localStorage` command once more. And this time, you will receive an error because we have successfully restricted access to the `iframe` element.
![localStorage](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ydpof58ed6y5rwg3ocb5.gif)

Sandboxing and executing the user's code using iframe is a fast and straightforward solution, though it might not be the best for all applications. Therefore, I advise that you do further research to provide a secured sandboxed environment for your users. I hope this article has helped you understand how sandboxing works and some things you should be aware of when building out your project.