Remote Plugins and Modules in AIR

I’ve been getting a lot of questions about how to use remote “modules” in AIR. “Modules” is in quotes because it can mean different things. In every case, it refers to running some SWF or HTML/JS content that is loaded at runtime from the network. The difference are in how the content is loaded and how an application can communicate with it.
Depending on the specifics of the modules you want to load there are different options about how to load and communicate with the content. Let’s explore the options!!


In web browsers, we run remote content all the time, and don’t have to worry about security. Images and pages from other domains can execute their own code, but can’t reach into ours. We can also choose to pull someone else’s code into our own and run it. Dynamic evaluation of Javascript is a powerful tool, and it can be elegantly used. SWF has the same security model: remote content (images, audio, video, SWF) can run without accessing our code, and we can choose to import remote code and content (loadBytes()).
Privileged local applications have a responsibility to protect their users. No one wants their app to have flaws that expose their users’ data or computers to attackers. AIR has strict but simple standards about which content (SWF, JS) can get application privileges. Only the files in the application’s security sandbox may use the local File APIs, Windowing APIs, etc. Files will be in this sandbox only if they are loaded from the application’s local directory via an app: URI, or are imported into that sandbox using explicit APIs.

Separate Sandboxes

SandboxedLoading.png
If you don’t trust the content, or don’t want to verify that it really is trusted, you can keep it at arm’s length. This is the default; remote content is loaded in a remote sandbox according to its domain. One difference in AIR is key: Communication is possible across sandboxes at runtime. Using the SandboxBridge API in AIR, content can expose a discoverable API to content across the border. Any data passed is copied to its destination. Complex data structures can be passed across the (deep-copy, without functions and custom class information).
This feels more like service-style communication. Loading a file is like getting a service endpoint. Your code’s integrity is protected by the loose coupling, but the service also has a bit of code that it gets to run in your client. Google Gears’s WorkerPool has a similar style, with message passing between threads that run in their own sandboxes. The big difference is that SandboxBridge messages are synchronous, and look like function calls and property gets.
SandboxBridges can be used at frame/iframe borders and at the LoaderInfo that is shared by parent and child when using Loader. Each side can expose APIs to the other. But it’s essential to resist the urge to bust the whole thing wide open. Don’t think it’s cute to just expose every AIR API to unprivileged content. Instead, expose high-level APIs that, when abused, will damage only your application, not the user’s whole system. A writeFile(file, data) API is just an invitation for attack. By contrast, savePreferences(data) will make your app less vulnerable to malicious content.

Importing

Importing.png
If you do trust the content, and want it to be able to share your runtime data, share your type definitions and execute in your space, you can import it into the application’s sandbox. This content will have full privilege. I can’t overstate this enough: content you import this way can completely take control of your application. And once it has control of your application, it can start doing evil things to the local machine. It can do anything your app can do.
So, why even bother with such a dangerous technique? Well, in some cases it really is what you want. If you’re trying to reduce the download size of your app, you can wait until you need some functionality before downloading it. Flex Modules, for instance, require that they be imported into the loader’s sandbox. The same technique works for localization data.
So to pull this content in safely, you need to prove that you can trust it. Given the ease of remote attacks (DNS hacks; man-in-the-middle attacks; owning up the “trusted” server; etc), imported modules must be signed, and the signature must be verified before loading the content.

  1. First, sign your modules. I’m pretty sure you can just use adt for this, then rip the signatures.xml out of META-INF. Then post the modules and signatures.xml

  2. When you download the modules, save them and signatures.xml somewhere in app-storage:/

  3. Use the XMLSignatureValidator class to validate that you downloaded modules that really were signed by you (or some known entity).

  4. Import the modules into your application sandbox. For SWF, use Loader.loadBytes(), pass a LoaderContext with allowLoadBytesCodeExecution=true. I doubt anyone will do *that* by accident.

In AIR 1.0, this is the best way to use Flex modules without taking dangerous risks. I expect there will be other techniques in future versions.
Import this way is not going to work for arbitrary third-party content. If you don’t know ahead of time who you trust to have signed it, you must not import it. Once again, we come back to The Spiderman Axiom: with great power comes great responsibility.
Blah. That’s way too long. But at least I have someplace to point people to when they ask!
Comments? Concise summaries?