Using an iframe for sandboxing?

2019-08-03 06:28发布

I am developing a system that allows userwritten javascript in widgets. To keep things secure, I plan to sandbox these widgets in iframes. Of course, for the sandboxing to be effective the iframe must have a different domain than the parent document.

I would really love to be able to dynamically generate the iframe with code similar to this:

template = '<html><body><script>/* user code */</script></body></html>'
src      = 'javascript: document.write("' + template + '")'
widget   = $('<iframe>').attr('src', src)

$('#container').append(widget)

...and then have the resulting iframe be treated as cross-domain from the parent window. Is this possible, and if so, how would it be done?

1条回答
混吃等死
2楼-- · 2019-08-03 07:08

Ok, I think I get what you need but it's a bit tricky. You want to create an <iframe> and populate it with the user Javascript client-side but still have the client sandboxed?

This is fairly non-standard. Usually the contents of the <iframe> are generated server side. But here it goes.

First some background: documents can not access the content of any document that is not from the same domain (including sub-domain) and port. But they can change their own security domain using the document.domain property. So what you need to do is lighten up the security then tighten it back up again for the user script to run.

So you can't do it the way you specified because if you create an <iframe> with a Javascript src the document.domain will match the parent frame. This means that the widget will have full access to everything.

So here's how you can do it:

  1. Set up two sub-domains of your main domain. Let's call them home.example.com and widgets.example.com.
  2. Create a basic HTML file on widgets.example.com and make sure it calls this javascript: document.domain = "example.com";
  3. Now create your page that will contain all these widgets. Set it's document.domain to the same value.
  4. Create all your iframes loading your basic HTML page from widgets.example.com into it.
  5. Set a variable inside the frame that contains the user template. Ex: myFrame.contentWindow.foo = "template";
  6. Switch the document.domain on the main window back to home.example.com so that the <iframe>s will no longer have access to the parent frame
  7. Trigger the template substitution in the frame

That last part is the tricky part. You can't just embed the code because if it runs automatically it will run before you can change the domain of the home document back, which will be a security issue. So instead you need to set it to a temporary variable inside the frame then somehow trigger the frame to replace its own contents with that template but only after everything is locked down. The easiest and most compatible way would be to trigger it on resize and then just change the width or height of the frame.

Now, alternatively, if the widget was populated server-side:

  1. Host widget on widgets.example.com
  2. Host page containing widget on home.example.com
  3. Done

But I assume that you have reasons for doing it all client-side.

The logical next topics: communicating between the frames and auto-sizing. But those are for another day.

Did I answer your question? I hope so because this was a lot of typing and I won't mind the reputation points if you vote up and accept my answer! ;)

查看更多
登录 后发表回答