User:Brion VIBBER/Secure code modules through iframe sandboxing
The HTML iframe element provides for embedding one web application inside another, with various degrees of sandboxing available through cross-origin protections and the sandbox attribute. The parent application and the child frame application can communicate with each other asynchronously by sending strings or JSON objects over the postMessage interface.
- Extension:SVGEdit - uses an iframe to embed a web application
- sending data in/out over postMessage
- iframe works remotely-hosted, in which case XSS worries in the app don't directly expose the MediaWiki site
- Extension:EmbedScript - experiments for in-content JS widgets
- sending code in over postMessage
State of the sandbox
- Using an external domain to enforce cross-origin barrier works in every browser
- Requires a domain to coordinate with.
- Either host data blobs on that site, or use a shim that allows postMessage'ing in some code and resources to use. (as EmbedScript extension did)
- postMessage sends JSON objects via structured-clone on most/all browsers -- test me!
- (some old ones may still be stuck on strings, requiring JSON.stringify/parse)
- iframe sandbox attribute is pretty well supported as of April 2016
- Allows creating an iframe without a separately-hosted domain, and restricting its scripting access.
- sandbox='scripting' (without adding 'cross-origin') should allow JS to run while still isolating it from access to the parent frame JS world, or the site's cookies, localStorage, indexedDB, etc.
- iframe srcdoc attribute is slightly less well supported, still missing on Edge
- can be used to provide HTML/JS source to load into the iframe, without a separate document that could be loaded outside a frame
- if we have a shim .html, it can allow HTML/JS to be injected from the parent frame over postMessage, as done by EmbedScript
- Biggest "hole" in the sandbox is web bugs
- HTML and JS in a frame can trigger remote network requests through <img>, <script>, <link>, XMLHTTPRequest, etc etc.
- This exposes user IP address to off-site servers (privacy issue definitely, security issue maybe)
- Runs risk that user-written code may pull in off-site resources deliberately or as a shortcut (sustainability, copyright issues; further security/privacy complications if remote code is loaded)
Content widget thoughts
"Content widgets" such as the interactive 'Game of Life' widget on W:es:Juego de la vida are an obvious application, as isolation from the main MediaWiki web page security context is pretty much a prerequisite for getting these made and distributed widely without a HUGE security review bottleneck.
There are two major technical issues:
- "web bug" problem exposing users' privacy when loading offsite resources
- temptation to use offsite resources (copyright & sustainability issues)
A good UX for creating, reviewing, approving, and using widgets would go a long way:
- jsfiddle-like UI for editing/running in isolation?
- code-friendly revision history/diff view & commenting UI
- use ContentHandler for custom storage & views
- store HTML+JS+CSS in a single blob versioned together?
- a good 'incoming review' queue
- static analysis to check for common problems?
- detect direct references to remote resources and highlight them
- workable versioning / release blessing
- a widget that's in use on articles shouldn't stop working because it's been updated and not yet reviewed!
- allow a user to preview their own code widgets at least on test pages
- allow other users to see those previews, with a security opt-in?
- maybe consider local code to be edited and 'published' code versions that get reviewed and can be used in main content
- trigger updates to the new version after a release review
- a good searchable "catalog" of published+reviewed widgets, that can be searched and widgets set up from within both visual and source editors
- probably need to be able to have shareable code libraries -- common graphing libraries, jQuery, etc could be reused frequently
UI plugin thoughts
There are two main targets for iframe-isolated UI plugins:
- Defense in depth for MediaWiki extension code installed by site operators
- especially when pulling in a large HTML/JS code base from another project like an SVG editor or WebGL 3d model renderer!
- avoid polluting main JS context with someone else's scary globals
- allow large JS modules to be unloaded when an extension dialog closes
- Safer way to write and share user-written code like today's user scripts and gadgets
- would require designing suitable async hook APIs, and some kind of registration system
- most of the concerns for content widgets above apply here as well (security/privacy, editing/review)
- a UI plugin may have more legit reasons to access an external site, such as integrating a service on Tool Labs with a good on-wiki UI
Extension code can roll its own loader & postMessage API, but having common infrastructure would be nice.
Security isolation for user-written UI plugins could make it easier to safely share tools similar to today's user scripts and gadgets:
- Page editor plugin could register a toolbar button that activates a dialog, then allows async access to the editor's text or DOM contents and selection state. Could implement custom search-replace, wikification, a fancy new citation formatting wizard, etc.
- Uploaded file editor plugin could register a custom editor action on File: pages, to implement vector or raster editing, client-side OCR, passing data into server-side OCR, etc.
- Fancier interaction requirements -- such as adding hover handlers to links -- could be mediated through install-time manifest, permission dialogs, ...?
Narrower APIs in the isolated frame have downsides and upsides:
- bad: porting existing code may have to make significant changes, and may have to add more APIs to support stuff over time
- good: future-proof - code is unable to dig into internals of HTML structure and JS API surface that weren't meant to be relied upon
- good: device portability - more likely to be able to use same plugin APIs on desktop, mobile, and even in native apps (via a web view)
It could also be very useful to provide 'blessed' libraries for the child frame to use on demand:
- jQuery, subset of mediaWiki.utils, etc
- ability to pull code libraries from other plugins?