Use common JS libs inside sandboxed iframes - javascript

I plan to build a module system for my webapp that uses sandboxed iframes and the postMessage API to securely run custom user modules. The iframe blocks all DOM access and should only communicate through an interface provided by me which checks some permissions and provides data.
The system itself is very simple and works fine with vanilla js code inside the modules, however I want to allow developers to use common frameworks/libs to ease development, i.e. by using Vue for data binding.
What is the best way to provide such functionality to the modules? Performance is a huge factor since several dozens of such modules might run at the same time. Is it secure to let sandboxed modules share libs?

Good advice: Unfortunately, iframe sandboxing goes both ways. In general (with a few exceptions: mainly postMessage and pages that satisfy the same-origin policy), an iframe is effectively a separate webpage and cannot be accessed from the host page, and vice-versa. It's probably a better alternative to just request that the individual developers use lightweight libraries.
Bad advice: If you hosted the other devs' files yourself, they could access each other, but having stuff accessible between iframes in this way is certainly not ideal- and doing it this way is a really bad idea, as it exposes you to all sorts of scripting-related attacks; not to mention the fact that the separate iframes would probably accidentally interfere with one another in unexpected ways if you shared Javascript variables between them. Don't do it this way unless you explicitly trust every single developer here to behave properly and code well (i.e. you're in the same workplace). Actually, just don't do it this way at all.
If you really really want to do this, though: an iframe whose target is hosted on the same website can access its parent page through the global variable parent (i.e. parent in an iframe is the same as window in the host, parent.$ would be the parent's jQuery object, and parent.document.getElementById is the same as document.getElementById). A parent page can access its same-origin iframes with document.getElementById("the id of the iframe").contentWindow (and .contentWindow.document, etc. will work here too), but again, if you hosted the code of potentially-malicious developers on your page to get around the same-origin policy, you'd be giving these developers access to your page and any information, including passwords, that your users type on it.

Related

How can my Add-on SDK content script interact with a website page script?

In my SDK add-on, I'd like to
call a function in a page script
export, read (get), write (set) or manipulate some variable or property in a page script
export a new function to or override an existing function in a page script
or post a custom event to a page that the page script can listen for.
How can my Add-on SDK content script communicate with a website?
There are a multitude of ways to interact with page scripts, the most common of which are covered in the official documentation, including all of the ways listed in the question.
Please read "Interacting with page scripts".
However, it should be pointed out that interacting with page scripts in a secure fashion can be hard. Be particularly aware that unsafeWindow is called unsafe for a reason:
Be careful using unsafeWindow: you can't rely on any of its properties or functions being, or doing, what you expect. Any of them, even setters and getters, could have been redefined by a page script. Don't use it unless you trust the page, and even then be careful.
Also, unsafeWindow isn't a supported API, so it could be removed or changed in a future version of the SDK.
Reading data from or executing functions of unsafeWindow is safe in the sense that it cannot directly lead to code execution in another (your content script) security context. The Javascript engine compartments will make sure of that.
But it is very true that you must never trust data coming from a website.
Always expect code to throw, Denial-of-service you with unexpected infinite loops or similar. And never ever explicitly or implicitly evaluate code in the context of your content script.
Also, never think you can actually trust a website, even it it is your own website. Websites can be compromised (hacked), owners can change in the future, the data could be changed en route (active Man-In-The-Middle attacks), or another add-on could have modified it, etc.

Third Party Polymer Elements

I'm trying to understand if polymer is built for a specific use-case-- third party web components.
What I need to accomplish is create a web component that takes as input from the caller's page an image url (attributes on an element is ok) and inside the polymer component it renders the image in a special way using HTML5 canvas.
To me, it seems like polymer isn't currently built for third-party usage. Reasons why:
one must have enough control over the caller's page to add platform.js to the <head>, specifically the <head>
my version of platform.js could potentially be different than the caller page's platform.js (or bare minimum i'm polluting the page with polymer's JS objs, right?)
in non-chrome browsers style and other tags are injected into <head>, possibly conflicting with the source page
one must have control over the caller's <body> tag if wanting to set options to avoid FOUC
Traditionally all my web components have been built via iframes and i'd like to modernize my approach with a view towards a "shadow-dom future."
Is there a way to use polymer in a third-party safe way? Perhaps a mashup with [lightningjs?
Polymer and Web Components are entirely structured around 3rd party usage, this is a central design pillar.
The broadest notion IMO is that developers will be able to go to the web and find numerous Web Components to choose from. This is not unlike being able to choose from an enormous set of JQuery plugins, but with a much greater degree of interoperability and composition because each instance can be treated as a traditional Element.
platform.js
Platform.js is modeling future browser capabilities called Web Components. There are practical realities of making this work right now, so yes, in order for a third party to use Web Components at all, they will need to opt-in in to platform.js (and all that entails). It's true that this fact makes it's difficult (today) to inject Web Components into somebody's page without their assent.
my version of platform.js could potentially be different than the caller page's
As above, platform.js is required upfront to use Web Components. This is why it's named the way it is. Unless the main page owner includes this capability, he's not providing a platform to which you can supply Web Components.
This is not dissimilar to modern libraries, e.g. JQuery. You can load numerous copies and/or versions of JQuery in one document if you aren't careful, but it's wasteful. Coordination is preferred.
With the exception of platform.js, Web Components is geared around N modules using M dependencies, and that all working together optimally. This is another way sharing is a pillar of the design.
in non-chrome browsers style and other tags are injected into , possibly conflicting with the source page
This all the price of polyfilling. If you need purity of environment, you will have to wait until Web Components are widely implemented natively. As a practical matter, the style tags are very specialized and are unlikely to conflict with anything.
one must have control over the caller's tag if wanting to set options to avoid FOUC
This is not strictly true, you can build Web Components that control their own FOUC up to a point. But it's a lot of extra work, and as a third-party, you really can't know what kind of loading mechanisms or idioms some developer is going to employ, so trying to orchestrate too much without his cooperation is going to be difficult.
Traditionally all my web components have been built via iframes
IFRAME is quite a bit different from Web Components. An IFRAME is a fresh context, and so you have a lot more safety net, but it's heavyweight and there are coordination costs.
Although platform.js, by it's very nature, is changing the shared platform, Custom Elements themselves need not mess with the user's global namespace or his CSS (although they can). Code can be restricted to the element's prototype, and CSS and DOM can be stashed inside ShadowDOM. The overall intent is that none of that need leak out of the Element, unless somebody wants it to.

Security in embedded javascript and HTML

I'm trying to find a solution for the following situation:
I've a web application made of HTML, javascript, AJAX, ad so on.
I want users to contribute to my application/website creating plugin that will embedded in it.
This plugin will be created using similar technologies (ajax, HTML, etc) so i need to allow plugins to run their own javascript code.
Each plugin will work in a page that will contain some user information and the plugin (like old fbml facebook applications)
The problem is that in this way the plugin can also made calls to get users information. (because since plugin's code is embedded it's domain will be the same of the main website, and the code will be entirely on my website).
So the question is: how can I avoid it and have a precise control about what information a plugin can get about the user?
The plugin will not be checked and can be changed anytime, so reading all the plugin code is not a solution.
I'm open to any proposal, possibly easy and effective, and possibily not putting the whole plugin in a iframe.
--
EDIT:
How did facebook do when there was the old way to create applications? (now it's only iframe, but there was FBML application way, how did they get this secure?)
Have you ever heard of exploits allowing arbitrary code execution. Which is one of the most dangerous attacks ?
Well, in this case you are explicitly and willingly allow arbitrary code execution and there's almost no way for you to sand box it.
1) You can run the "plugin" within an iframe from a different subdomain to sandbox it in there, as you've mentioned. This way plugin can't reach your cookies and scripts.
Note that, if you want the plugins to communicate with your services from this domain, then it will be cross-domain communication. So you either need to resort to JSONP or use new cross domain access control specifications. (i.e. return appropriate headers with your web service response -- Access-Control-Allow-Origin "plugins.domain.com")
2) Create your own simple scripting language and expose as much as you want. This is obviously tedious, even if you manage to do that, plugin developers will endure a learning curve.
Facebook had their own "JavaScript" coined FBJS which did the sandboxing by having control over what could run.
Without a juicy backend, this really limits the impact of your script.
However you still have to worry about DOM based xss and Clickjacking
It's 6 years later, but I feel it's important to provide a modern solution to this. The new(er) sandbox attribute can be used to limit the capabilities of an IFrame.
A simple implementation of this system would allow only the allow-scripts permission to the IFrame, perhaps with a simple JS file which would be included along with each plugin containing a few custom library functions.
In order to communicate with your HTML page, you would use postMessage. On the plugin end, a library like I mentioned above could be used to transfer commands. On the user side, another system would have to validate and decode these requests then execute them.
Since a sandboxed IFrame doesn't have cross origin capabilities, it cannot directly modify the page. However, this also means the origin of the postMessage can't be verified, so some sort of code would have to be created for security reasons.

How can javascript (or a browser extension) detect the use of restricted functions?

I'm developing a scripting extension, similar to Greasemonkey or Chrome's content-script engine. This extension will allow script writers to do very dangerous things like access local files.
If I ever release this extension to the public, I would like it to be able to warn novice users if a script will use a "dangerous" function. I'd like this warning to be as hard to circumvent as possible.
For example, the extension can search for the protected string GM_openSQL_Connection and warn the user -- maybe like this:
Assume that the base web page will never be able to access GM_openSQL_Connection thanks to sandboxing mechanisms. Likewise, no <script> node will be able to.
But, the script writer could still circumvent the simple search, from above, with something like:
eval (decodeURI ("GM_op%65nSQL_Connection (...);") )
So the question is what are the kinds of ways in which an evil scripter can fool the check for restricted function usage, and how might I prevent such mischief?
Note: false warnings can be okay. For example if the script author uses the text "GM_openSQL_Connection" in an otherwise static string, then he will just have to put up with the (false) warning.
What are the ways in which an evil scripter can fool the check for restricted function us[age]?
There are thousands of combinations, for example, with eval(), new Function(), combinations of String.fromCharCode() and decodeURI() (like in your example).
How might I prevent such mischief?
Could you overload/shadow specific bad functions/objects/variables?
GM_openSQL_Connection = function() {
warnUser();
};
To set a flag if the extension attempts to access a forbidden function or variable, simply have a var isDangerous = false which is set to true if a forbidden function is called or the get/set on a forbidden property is accessed/modified.
If the isDangerous is true, then you can mark that extension as potentially having dangerous function/property calls/accesses.
Trying to scan the script to detect whether it uses any of these interfaces is the wrong approach. It is too easy to evade through obfuscation, as you seem to be discovering. It's fundamentally insecure: there's no way to make it work.
Here is a better approach. Require the script-writer to include a manifest that declares what special APIs it needs access to. Then, run the script in a secure Javascript sandbox which only exposes the allowed APIs and APIs it has requested, but nothing more. If the script doesn't request GM_openSQL_Connection in its manifest, don't expose that API to the script.
Because Javascript is a dynamic language that allows monkey-patching and unrestricted access to the global object, it takes some doing to build a secure sandbox that restricts what APIs the script can access. Therefore, I recommend that you use an existing sandboxing solution. One approach is to run the user script in a sandbox, and give the sandboxed code a library that's full of stubs for the sensitive APIs, where the stubs just use postMessage to send a RPC request to your extension code. This avoids having references that cross the sandbox boundary, which is good as (depending upon sandboxing technology) those kind of references typically carry a substantial potential for security vulnerabilities.
Then, you can drive your user warnings based upon the contents of the manifest. Important: please think carefully about this from a user's perspective. Will ordinary users be able to make sense of the warnings? Will they be able to make sensible decisions? Will users be in a better position to make good decisions than you will? Will users be overwhelmed by constant warnings, and just start ignoring them and clicking 'ok' (the cry-wolf effect)?
For information on technology for Javascript sandboxing, please read the following question on IT Security: How to scan Javascript for malicious code?. In the future, you might get answers on the IT Security site for this kind of question.

Embedding Javascript in Javascript (I'm serious)?

I'm working on a project where players can place graphical objects on a website and animate them with scripts. As the scripts are going to be shared to all participating clients, the scripting environment must be sandboxed, so that users can't ultimately destroy other users experience for all parts of the page.
It is crucial that the scripts can access shared visual content. Therefore I can't isolate them in iframes entirely - besides that I'm wondering if there's a smoother approach to separate contexts.
I have been dabbling with a native version, where I used separate contexts using the V8 javascript engine, but now I want to bring this to the browser - even if it's just Google Chrome only.
Got any ideas?
Sandboxing JavaScript is inherently difficult, chances are that the script will manage to break out no matter how hard you try. A better course of action might be loading the scripts into an iframe without direct access to the main frame and allowing it to communicate with the main frame via window.postMessage(). You could then define an API that the frame is allowed to use this way without being given too much power.
Edit: Same thing is possible with Web Workers as noted in Is It Possible to Sandbox JavaScript Running In the Browser?, browser support for web workers isn't quite as widespread as for window.postMessage() however (compare http://caniuse.com/#search=postMessage and http://caniuse.com/#search=workers).

Categories

Resources