6

I am planning to create an open source education web app where people can add and edit the content (a bit like Wikipedia).

However I wish to add another feature that allows the user to add their own interactive content using JavaScript. (similar how JSFiddle does it)

What are the security concerns in doing this? Optional question: How can these issues be overcome?

Yahya Uddin
  • 26,997
  • 35
  • 140
  • 231
  • Do you mean "own interactive" - where every user does only execute scripts installed by himself or "interactive content" where any user can upload code that will be executed by others? – Bergi Jan 19 '14 at 17:44
  • where user can upload code that will be executed by others – Yahya Uddin Jan 19 '14 at 21:50
  • This is dangerous. Avoid it if you can (e.g. by only allowing them to configure given modules); if you need/want it you should use some peer-review process so that malign code is rejected. – Bergi Jan 19 '14 at 22:19

2 Answers2

9

Yes you could use HTML5 Sandbox to only load user scripts in an IFrame.

You should only host user content from a different domain than your main site. This will prevent any XSS attack if an attacker convinces a user to visit the page directly (outside of the sandbox). e.g. if your site is www.example.com you could use the following code to display the sandboxed IFrame (note .org rather than .com, which is an entirely different domain):

<iframe src="https://www.example.org/show_user_script.aspx?id=123" sandbox="allow-scripts"></iframe>

This will allow scripts, but forms and navigation outside of the IFrame will be prevented. Note that this approach could still risk a user hosting a phishing form to capture credentials. You should make sure that the boundaries between your site and the user content are clear within the user interface. Even though we haven't specified allow-forms, this only prevents a form from being submitted directly, it does not prevent form elements and JavaScript event handlers from sending any data to an external domain.

The HTML5 Security Cheat Sheet guidance on OWASP states this is the purpose of the sandbox:

Use the sandbox attribute of an iframe for untrusted content

You should test whether sandbox is supported first, before rendering the IFrame:

<iframe src="/blank.htm" sandbox="allow-scripts" id="foo"></iframe>
var sandboxSupported = "sandbox" in document.createElement("iframe");

if (sandboxSupported) {
    document.getElementById('foo').setAttribute('src', 'https://www.example.org/show_user_script.aspx?id=123');
}
else
{
    // Not safe to display IFrame
}

It is safer to do it this way by dynamically changing the src rather than redirecting away if sandboxSupported is false because then the iframe will not accidentally be rendered if the redirect doesn't happen in time.

As a simpler alternative, without the need to check whether the sandbox is supported, you can use the srcdoc IFrame attribute to generate the sandboxed content, making sure that all content is HTML encoded:

e.g. <html><head></head><body>This could be unsafe</body></html>

would be rendered as

<iframe srcdoc="&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;This could be unsafe&lt;/body&gt;&lt;/html&gt;" sandbox="allow-scripts"></iframe>

Or you could construct a data blob object, being careful to HTML encode again:

<body data-userdoc="&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;This could be unsafe&lt;/body&gt;&lt;/html&gt;">

<script>
var unsafeDoc = new Blob([document.body.dataset.userdoc], {type: 'text/html'});

var iframe = document.createElement('iframe');
iframe.src = window.URL.createObjectURL(unsafeDoc);
iframe.sandbox = 'allow-scripts';
</script>

Of course you could also set the unsafeDoc variable from a JSON data source. It is not recommended to load an HTML file, as this has the same problem of it having to be from an external domain, as the attacker could just entice the user to load that directly.

Also, please don't be tempted to write user content into a script block directly. As shown above, data attributes is the safe way to do this, as long as correct HTML encoding is carried out on the user data as it is output server-side.

In these cases you can leave src as blank.html as older browsers that do not support srcdoc will simply load that URL.

As @Snowburnt touches upon, there is nothing stopping a user script from redirecting a user to a site where a drive-by download occurs, but this approach, assuming a user is up to date on patches, and there are no zero day vulnerabilities, this is a safe approach because it protects its end users and their data on your site via the same origin policy.

SilverlightFox
  • 32,436
  • 11
  • 76
  • 145
  • Doesn't the same origin policy protect users form drive-by downloads? – whereswalden Jan 09 '15 at 21:41
  • @whereswalden: No, a drive-by download is effectively a browser exploit - not an actual download. The Same Origin Policy cannot protect against bugs in the browser. – SilverlightFox Jan 09 '15 at 22:14
  • Is this still a viable option? I want to develop a platform where users can build their own "modules" with html, js and css. – JCAguilera Oct 29 '21 at 21:51
  • 1
    @JCAguilera Yes, [browser support is good](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe). As mentioned, I'd recommend `sandbox` with the `srcdoc` option or the `Blob` approach, as these methods don't require another domain to be purchased. – SilverlightFox Nov 01 '21 at 11:47
1

One big issue is cross-site scripting where users add code that tells the browser to open and run code from other sites. Say they add something that creates an iFrame or a hidden iFrame pointing to a site and starts downloading malicious code.

There's no simple way around it (thanks to Bergi in the comments) to make sure no elements are created and no ajax calls are made.

I've been a member of sites that provided this functionality, but for those sites I paid for my own space so any vulnerabilities I add are inconveniencing my own clients, in that case it's a little more okay to let that slip by since it's not a security leak for everyone.

One way around this is to create customizable controls for the users to use to add interactivity. The plus is that you control the javascript being added, the minus is that your user base will have to request and then wait for you to create them.

Snowburnt
  • 6,523
  • 7
  • 30
  • 43
  • 1
    *intense parsing of the javascript*? That hardly will work. Did you know that one can write every javascript [without alphanumeric characters](http://patriciopalladino.com/blog/2012/08/09/non-alphanumeric-javascript.html)? Code filters are doomed to fail. – Bergi Jan 19 '14 at 17:43
  • But in that case how does JS Fiddle handle this issue, as they allow people to submit JS. Also would something like the sandbox feature in iframe for HTML5 work? – Yahya Uddin Jan 19 '14 at 21:49
  • @user3111466: jsfiddle does allow scripts to run havoc - you just never opened a malign link, did you? Afaik, the embedded results come from a subdomain so that the scripts can not do malicious things for logged-in users because of the same-origin-policy. – Bergi Jan 19 '14 at 22:15
  • @user3111466 jsfiddle is intended to be a sandbox and it's use is generally intended as a de facto trust between the user base. Personally, I wouldn't put out any production system allowing free use of javascript with a user base unless it's a situation like I described where a particular user is responsible for their namespace and they'll only be screwing over their customers by infecting their own site with malware. – Snowburnt Jan 19 '14 at 22:56