3 March 2008
My goal in this document is to provide a high-level overview of the AIR security model, and the rationale behind it.
Adobe AIR allows developers to use their existing web development skills in HTML, Ajax, Flash, and Flex to build and deploy desktop applications. Although these applications may be based upon web technologies, it is important to keep in mind that the end result is a desktop application, and as such the primary security model for AIR is that of a desktop application, rather than a web application.
A desktop application has certain characteristics. On the one hand, desktop applications generally have a lot more privileges than a similar web application, as they have been installed by the user to a specific desktop machine, implying a degree of trust that is greater than that of arbitrary web content. On the other hand, the privileges inherent in a desktop application require a greater degree of caution as certain coding practices and patterns that may be common in web applications may never be acceptable in a desktop application.
AIR applications can be built using a combination of Flash and HTML/Ajax. AIR applications can also leverage PDF for document rendering, although an AIR application cannot be based upon a PDF file alone.
Regardless of whether an application is built primarily in Flash or HTML, all AIR applications have some characteristics in common. Within a given AIR application, there is a set of AIR specific APIs that are available to provide access to local system and network resources that would not be normally available in a web application contained in a browser. Each AIR application also contains a number of different sandboxes, depending on what type of content is being loaded, and for what purpose:
app:/ URIscheme) can be placed in the application sandbox.
For more information on AIR sandboxes, refer to the Sandboxes section of the AIR developer's guide for HTML developers.
There are a number of design and implementation patterns common to web applications that are too dangerous to be combined with the local system access inherent in the AIR application sandbox. In a desktop application, the user grants system access (albeit sometimes unknowingly) to the application by downloading and then installing and running the application. This in theory allows the user to inspect and approve the application before installing or running it for the first time.
This in return limits the ability of the application to extend itself by silently and dynamically installing additional components or running code loaded from a remote server. For example, a fundamental desktop practice is to inform the user when downloading and installing updates, plug-ins, or other extensions to an installed application. Even applications that appear to do this automatically give some notice to the user, as well as providing a configuration option to disable automatic updates. When apps attempt to bypass this user consent, they run the risk of being labeled a privacy threat, if not a security vulnerability, which is why runtime script importing of remote content has been disabled in the application sandbox.
Imagine a scenario where your desktop application automatically imports some script from your website every time it runs, perhaps to render today's stock charts or to provide the latest application functionality. In the event that your server is compromised, or if you do not perform that code loading very diligently (that is, sign the script with your certificate and subsequently verify the validity of the signature), then an attacker could take over every machine that runs your application simply by compromising the server hosting that one script. So the user deciding to install a given application does not automatically grant the right to that application to download and execute additional code without additional, explicit user consent.
Another concern lies with practices that, while they may not be intended to load external code or script, permit injection of remote script (commonly known as cross-site scripting or XSS) where the developer never intended. The
eval() is often used to generate code from templates combined with data potentially loaded from a remote domain. Unless the developer is extremely diligent in scrubbing loaded data for every possible form of code injection, then any such data containing malicious code could compromise the user's system if
eval()'ed in the application sandbox. This is why using
eval() and similar APIs to generate code at runtime in the application sandbox is prohibited.
Finally, using any remote data in AIR specific APIs should be done with extreme care. For example, if a remote server can provide a file name and file contents for the application to download, it could write the file to a sensitive area of the file system, possibly resulting in installation of a malicious rootkit. This may seem farfetched, but it is a common mistake that is easily made, even when you believe you have exercised sufficient care. Suppose you have built an application that allows the user to browse and save photos from a remote server. At some point, your application would probably provide a function that looks something like this:
savePhoto(var filename, var content);
You may even take the extra step of ensuring that you provide a root directory—for example, C:\Photos— that you prepend to the file name variable. So imagine if the data provided by the remote server is something like this:
filename = "sailboat.jpg" content = <contents of an actual JPEG>
Your code prepends C:\Photos, resulting in:
filename = "C:\Photos\sailboat.jpg"
Looks pretty good, right? But what happens if the remote server provides you instead with:
filename = "..\Windows\notepad.exe" content = <contents of an EXE rootkit>
When you prepend your root directory to the file name, you end up with:
Filename = "C:\Photos\..\Windows\notepad.exe"
This will still overwrite the Notepad application in the Windows directory, and end up executing the rootkit the next time the user attempts to run Notepad. This is a simple example, but it illustrates how easy it can be to make such a mistake.
For additional information, see the sections "Best security practices for developers" and "Writing to disk" of the AIR developer's guide for ActionScript developers.
The security model for the HTML application sandbox in AIR varies significantly from the sandbox available in the browser. The reason behind this is there are a number of design and implementation patterns common to HTML web applications that are too dangerous to be combined with the local system access inherent in the AIR application sandbox.
Patterns such as remote script importing and use of dynamic script generation via
eval() and injection of code into innerHTML and outerHTML DOM elements—while already very dangerous—are very common in HTML applications. Their familiarity unfortunately does not make these practices acceptable in the application sandbox in AIR. As such, you will notice significant restrictions when trying to import script or generate code dynamically in the application sandbox. If you really need to implement such potentially risky runtime patterns, you will have to do so in a non-application sandbox (see below).
There are characteristics of the HTML security model that can be surprising. For example, the most granular security sandbox is an entire frame (whether frame, iframe, or window). This means that all code within a given frame is in the same sandbox and has exactly the same privileges, regardless of how it was loaded into that frame. As far as the browser (or AIR) is concerned, it can't really tell the difference between code that is originally part of the page versus code that is imported from outside the page versus code that is generated by an
eval() function. This means that the only way to safely handle trustworthy and untrustworthy content is to separate them into different frames or sandboxes.
The recommended technique in these cases is to create a non-application sandbox to perform the risky operations, and then interact with that sandbox via the SandboxBridge API. The SandboxBridge is a bi-directional serialization API designed to allow domains/sandboxes that otherwise cannot trust each other entirely to interact.
Application extensions such as plug-ins are best implemented via the SandboxBridge. After obtaining user consent, you can store the plug-in in a non-application location (such as
app-storage:) and load it into a non-application sandbox. By exposing a well-defined plug-in API (much like the NPAPI does for most browser plug-ins), you can safely interact with your own plug-ins, or even third-party plug-ins developed for your application, without trying to import them into your application sandbox. In addition to being safer from a security standpoint, this type of well-defined plug-in API is a more stable solution, reducing the chances of plug-in breakage with subsequent updates to your application.
Note that the SandboxBridge is not fail-safe. Code in the application sandbox should not expose any APIs via the SandboxBridge that are not safe to be called by any arbitrary remote code. As such, you should not expose any system or sensitive application APIs directly via the SandboxBridge.
However, you could expose, for example, the
eval() function from a non-application sandbox back into the application sandbox, as any code subsequently evaluated within the exposed
eval() function then will be executed within the context of the non-application sandbox. This would not permit access to sensitive APIs or application data (unless you had expose those already to that particular non-application sandbox). As general guidance, it is usually ok to expose functions and data from a non-application sandbox into the application sandbox, but potentially risky to expose functions and data from the application sandbox into a non-application sandbox. Thus, if you want to use a specific non-application sandbox for these risky practices, you should not use it for anything remotely trustworthy or provide it with any sensitive APIs or data.
For additional guidance regarding usage of the SandboxBridge, see the "Working securely with untrusted content" section of the AIR developer's guide for HTML developers.
AIR applications are usually installed in one of two ways:
These two scenarios always use the AIR application installation experience, which is largely the same for all applications. The only significant differences in experience are determined by whether your application has been signed by a commercial, recognized code-signing certificate or a free, self-signed certificate.
For an example of the seamless install badge experience, see the article Distributing Adobe AIR applications via the Web in the Adobe AIR Developer Center.
All AIR applications must be signed by a code-signing certificate. The only question is whether the certificate in question is what is commonly know as a self-signed certificate, which means that it is not recognized as being trustworthy by a typical user's machine (unless the user chooses to import that specific certificate into his or her certificate trust store), or a commercial code-signing certificate purchased from a major certification authority (CA).
The recommended approach is to use a commercially obtained code-signing certificate, as that will be recognized by the AIR installer on almost all user machines. This permits the name of the publisher to be recognized and provides a better installation experience for the user.
For detailed information regarding code signing for AIR applications, please refer to the section "Developing AIR applications with Adobe Flex 3" of the Adobe developer's guide for ActionScript developers as well as Todd Prekaski's article, Digitally signing Adobe AIR applications, and Oliver Goldman's Code signing in Adobe AIR.
Being a desktop application runtime, the AIR security model is significantly different from the web browser security model. The application sandbox in AIR provides direct access to system APIs, but in return a number of APIs have been restricted or outright prohibited. Specifically, importing of non-application (that is, not loaded via
app:/) content and dynamic generation of code within the application sandbox is heavily restricted.
However, the privileges inherent in a full desktop application mean the developer can sometimes find ways around these restrictions. The reality is that doing so will almost certainly introduce a large amount of security risk into the application and for the end users of the application. Thus Adobe strongly recommends that developers stay within the restrictions placed by the AIR security model, and carefully consider the cost of implementing rigorous security mitigations for bypassing them. In most cases the development cost of these mitigations will significantly exceed the cost of finding an alternative solution that stays within the bounds of the security model.