AIR:HTML Security FAQ
From Adobe Labs
Adobe AIR HTML Security Changes FAQ: Beta 3
Why?
Why change the current model when it seems to be simple to understand and powerful?
The current browser security model is prone to a number of serious security issues (see the white paper "Ajax and Mashup Security" from the Open Ajax Alliance), and the system-level API‘s inherent in AIR can increase that risk. Developers should not have to become security gurus to create safe AIR HTML applications.
What kind of security threats are we talking about?
One of the main threats facing HTML applications, whether desktop or web, are injection attacks which result in malicious code execution. Code is usually injected via a few common vectors such as via URL handling (“javascript:” and other dangerous schemes), eval() and assigning external HTML content to DOM elements such as innerHTML and outerHTML.
These vulnerabilities rely on the developer assuming that they are dealing with content that is harmless, when in fact it contains malicious code. Malicious code can also be injected into a trustworthy service like Google Maps, if the loading operations happen over HTTP (especially in open wireless environments like internet cafes).
To provide a specific example, imagine an HTML-based AIR application that extracts comments from your online blog and displays them. Let's assume that the remote commenting system has no protection in place and users can write comments like:
<a href="#" onclick="var f=new air.File('c:\\something.txt'); f.deleteFile();">
This is a link to a cool website</a>
When such a comment is displayed inside the AIR application, the user will see the link and might be tempted to click on it. The result will be a file deletion or potentially worse depending on the code contained in the comment.
Aren’t these common patterns in web applications now? What’s the big deal?
These patterns do currently exist in AJAX browser applications in particular and that is part of the concern. Increasing criticism is being directed at browsers and AJAX frameworks for not effectively addressing these threats proactively. Awareness is rising that some current design patterns are extremely dangerous:
- http://www.fortifysoftware.com/news-events/releases/2007/2007-04-02.jsp
- http://arstechnica.com/news.ars/post/20070802-security-experts-warn-developers-about-the-risks-of-premature-ajax-ulation.html
- http://getahead.org/blog/joe/2007/03/05/json_is_not_as_safe_as_people_think_it_is.html
- http://www.openajax.org/member/wiki/WP3_-_Ajax_and_Mashup_Security
The root of the problem is not strict JavaScript Object Notation (http://json.org/) itself, but the fact that the way this data is parsed is simply an eval(). This means that any arbitrary JavaScript (not part of the JSON spec) can also be injected and executed.
There is sometimes an assumption that damage from data/code loaded via JSON is limited by existing domain sandbox restrictions. This is not correct. The most granular sandbox boundary for data and code inside the browser is a frame or iframe. Everything within that DOM is within the same sandbox, regardless of its origin (with the notable exception of cross-domain media content such as JPEG and sound files, but these don’t constitute data or code in the truest sense).
This may not be great in the browser, but has been acceptable for now. How is this any different in AIR?
Despite the vulnerabilities, ultimately browser-based applications are strictly sandboxed. Isolated from the user’s machine and bound by the same origin policy, browser applications have a unique symmetry. The damage potential from an injection attack in a given website is directly proportional to the value of the website itself.
As such, a simple website such as an unauthenticated chat or crossword site does not have to worry much about injection attacks as much as any damage would be annoying at most. A banking site or online brokerage on the other hand could cause a user to suffer significant financial damage and is likely to invest significant resources in hiring developers experienced with security, and independent 3rd party security audits.
In AIR, even a very simple application (RSS reader, news aggregator, crossword game) could contain an injection flaw resulting in a severe compromise of the user’s machine via the injection of malicious code that would install a rootkit. Moreover, the current design and implementation patterns encourage using these dangerous practices (JSON loading, eval(), setting innerHTML).
Are the changes discussed in this FAQ the final design for AIR 1.0?
No. Our goal is to iterate this design based on your feedback. Please let us know your thoughts, concerns and feature requests by contacting us through our feedback page.
How?
So what does this new security model look like?
An HTML AIR application contains one or both of two kinds of sandbox frames. One is named the “Application” sandbox. Code in this sandbox has full access to AIR APIs, but in turn cannot generated code dynamically after the initial page load. Essentially, the JavaScript parser is disabled after this point, so document.write() and similar APIs throw an exception, and setting of innerHTML is permitted but any script it contains is ignored. The only exception to this rule is that including of other local application content (from app-resource:/) is still permitted. This allows as much functionality as possible without exposing dangerous API‘s directly to tainted data (i.e., externally loaded data). A very limited form of eval() is also available after load, but restricted to evaluating object literals and constants, which basically means you can use it for strict JSON notation but not generation of arbitrary code.
The other sandbox is called the “Non-application” sandbox frame. This frame behaves essentially as a typical browser sandbox for local trusted HTML (local trusted HTML being defined as local HTML where full scripting is enabled). Code in this frame can use full eval(), execute code via assignments to innerHTML, and other dynamically code techniques. Being local application content, it is also NOT bound by same-origin policy, which means it can optionally do cross-domain data loading (XMLHttpRequest). In return for these dangerous behaviors, it is not permitted direct access to AIR system APIs.
Other local and remote content is treated largely the same way as it is in the browser.
The SandboxBridge API permits communication between different sandboxes, such Non-applicationApplication and Non-application or Application and remote. SandboxBridge allows the app to serialize data between the two sandboxes.
To see an example of how the new security model works, please download the following file: air_htmlsecurity_sample_100107.zip.
Where can I find additional details about the HTML security model?
Our Developer’s Guide provides detailed information about the HTML security model. Please note that this is a draft version of the document and will continue to be updated.
Download the latest draft of the AIR HTML Security Developer’s Guide: HTML Security Developer Guide.
How would someone code in this new model?
The “Non-application” sandbox is effectively the local trusted HTML browser sandbox. This behaves largely the way AJAX developers are used to, and allows easy porting of existing applications and patterns to AIR. You could take an existing crossword game from the web, for example, and insert it entirely into the Non-application sandbox frame.
Once the application wants to begin accessing AIR API‘s, you can implement the relevant API‘s in the Application sandbox. Using a simple crossword game as an example, the developer would implement functions like saveGame(), loadGame(), etc. in the Application sandbox frame, then expose them to the Non-application sandbox frame via SandboxBridge.
Capability |
AIR Application Sandbox |
AIR Non-application sandbox |
Default access to AIR APIs? |
Yes |
No |
Access to functions written in Application Sandbox that use AIR APIs via SandboxBridge? |
N/A |
Yes |
Can load remote script? For example, <script src=“remote_url”></script> |
No |
Yes |
Can execute cross-domain requests (XMLHttpRequest)? |
Yes |
Optional |
Support for getting strings to code after load event?
|
No
|
Yes |
Ajax frameworks will work without any changes? |
No |
Yes |
How is this similar to other models?
This model is a result of trying to maintain a high degree of backwards compatibility with the legacy AJAX model while reducing the risk from exposing system APIs to that model. The closest analogy may be the current client-server model. In this model, the browser handles much of the presentation and some dynamic 3rd party data loading (via JSON), while the server does most of the sensitive processing, and provides OS-like facilities such as storage, cryptography, etc.
What exactly is disabled or restricted in the Application sandbox?
- eval() restricted to evaluating only object literals and constants (i.e. JSON compliant)
- new Function()
- window.setTimeout()
- window.setInterval()
- parsing script elements inserted with innerHTML or outerHTML (setting non-script static HTML with .innerHTML is fine)
- parsing handler attributes (e.g. onclick="myFunction();") inserted with innerHTML or outerHTML
- “javascript:” URI scheme
- creating script tags and setting textContent
- importing of JavaScript files from outside the Application sandbox (i.e. from other than “app:” URI scheme)
Will Ajax frameworks break in the new security model?
Ajax frameworks running in the Non-application sandbox will run just like they do in a web browser. However, Ajax frameworks running in the Application sandbox may break if they include eval() like functions described in the previous question.
By default, root content resides in the Application sandbox. Browser sandboxes are defined by frames or iframes inside of the Application sandbox.
Why am I getting an "Error: Parsing Disallowed" message when running my AIR Application?
If you receive an error "Error: Parsing Disallowed" message, you have included code in your application that is trying to make a call to eval() or other dynamic script loading technique from within an Application sandbox. AIR Beta 3 prevents such calls and will display this error when it attempts to parse such code. Numerous Ajax frameworks depend on these techniques which, while permitted in the browser, will not work in AIR's Application sandbox. However, by moving your code to AIR's Non-application sandbox (an iframe with special attributes), these techniques are permitted and your error messages will go away.
See the next section for how to migrate your application to the Browser sandbox.
How should I migrate my application over to the new model?
If your application does not dependent on code described in eval() or eval()-like code described in question four, your application will run fine without any change.
However, if your application depends on a framework that depends on eval(), you will need to perform the following steps to migrate your code over to the latest builds:
1. Back-up your original application files. 2. Rename your original root content file to <myUI.htm>. 3. Create a new file named <myRoot.htm> and include an IFRAME pointing to <myUI.htm>. The IFRAME code should look something like this:
<iframe id="UI"
src=”myUI.htm”
sandboxRoot=http://YourRemoteDomain.com/
documentRoot="app:/"
width="100%"
height="100%">
</iframe>
Please note that the height and width attributes are optional.
4. Move the AIR API specific functions into the root content file (<myRoot.htm>). Since root content lives in the Application sandbox by default, it will have access to the AIR APIs. 5. Create a parentSandboxBridge to expose the Application sandbox functionality (<myRoot.htm>) to the Non-application sandbox (<myUI.htm>). See the sample code on the prerelease forum for an example. 6. Allow the Non-application sandbox to communicate with the Application sandbox by creating a childSandboxBridge. This will allow data and functions to be passed between the two sandboxes across the bridge. Inside the Non-application sandbox (<myUI.htm>) use the exposed functions on the parentSandboxBridge property to gain access to your AIR-related functionality.
Doesn’t the SandboxBridge mechanism run the same risk? Won’t developers just export all the dangerous stuff back into the Non-application sandbox?
The SandboxBridge mechanism does not guarantee security. Much like a client-server model, the key lies on how Application sandbox API‘s are exposed to the Non-application sandbox.
As part of this model, the server should never trust the client, and the client should never trust data loaded from 3rd party servers (i.e., servers other than the one it came from). Likewise, developers do not use JSON or other code loading on the server as that could easily result in compromising the server which in turn has access to OS.
So whether we are talking about an actual client-server model in the browser or the SandboxBridge mechanism in AIR, the server/application should not expose primitive system API‘s like writeFile(), readFile(), etc., as these could be exploited by a malicious client/browser. Using the crossword game example, the Application frame should instead expose API‘s such as saveGame(gameState:Array), loadGame() that can be safely be called by untrusted content. Note “safely” in this case means that the user’s computer remains safe, even though the user’s game could be corrupted.
Another thing to keep in mind about the SandboxBridge mechanism is that a SandboxBridge is assigned to a given frame, but not to a particular piece of content or remote domain. That means if you set up a parentSandboxBridge for content Non-application content loaded from an “app:” URL, and later the application or the user navigates that frame away to some remote content, that remote content will still be able to see and access that parentSandboxBridge. Thus, you should be careful to not reuse a frame or iframe in situations where you have exposed it to potentially sensitive APIs across the SandboxBridge.
But other desktop runtimes don’t have this model -- why does AIR?
Other platforms, such as .Net, Java and C/C++ have strong separation between code and data. They are compiled formats that do not suffer from implicit conversion of data to code like JavaScript does. In C/C++ for example, the equivalent to an injection attack is a buffer overflow. However, that requires an explicit coding mistake on behalf of the developer, and is much harder to discover and exploit.
As such, this model is necessary to provide equivalence to those platforms.
Can developers use existing AJAX frameworks in this new security model?
Existing AJAX frameworks should work within the Non-application sandbox. Most current versions of AJAX frameworks will not completely work in the Application sandbox, as many rely on eval() and cross-domain JSON loading. It largely depends on how much a given framework depends on eval() and similar behaviors, and which parts of the framework the developer wants to utilize.
Why restrict eval() for all Application content if there are legitimate use cases for using it?
eval() and its equivalents are being restricted in the Application sandbox because the common patterns where eval() is used are also the same patterns that represent the highest risk (i.e. cross-domain JSON, eval() for dynamic generation of code containing inline data from 3rd parties). There is no reliable way to determine when some data is safe to eval(), and when it is not.
How are applications that don’t leverage remote content vulnerable to injection attacks? What if I don’t load remote content in my application but leverage web services?
Applications that do not load any external data are not vulnerable to injection attacks. But that also means they are less likely to require dynamic code generation. Many applications rely on eval() for lazy loading of code, but that can be achieved through other means such as script including.
Loading of external data from web services is not any safer than JSON if any of that data is used inside of an eval().
Will this new model make code more complex to write and maintain?
Porting existing applications will require some new code, but that cost should be considered against implementing alternate mitigations, such as complex data escaping mechanism to prevent code injection attacks, and either a parser or a remote sandbox to provide safer JSON data loading. For an overview of the types of injections you would need to prevent via data escaping, see [1].
If AIR apps are full privileged anyway and end users choose to install these applications from developers/publishers they trust, why does this matter?
This is not about installing malicious applications, but rather about preventing legitimate applications from being exploited by malicious data. It is very important that AIR does not set developers (and users) up for failure by placing upon them an unreasonable burden of knowledge about security when developing even the simplest applications.
Is this model to become a standard in the browser?
There is not currently a formal RFC that would address the threats inherent in the current AJAX model. Adobe supports open standards, and we are investigating how we could contribute to solving these problems in a more universal fashion.
Is there a simple example that shows how the two sandboxes can communicate together using a SandboxBridge?
Yes. Please download the following sample application: air_htmlsecurity_sample_100107.zip.
Is there source code available for applications that show how the new model works?
Yes. Source code is available for all our sample applications including ones such as Fresh which are built using HTML.
Is there a tutorial that demonstrates a real-world example?
Yes. See the article "Building an expense tracker on the new Adobe AIR HTML security model" on the Adobe AIR Developer Center.
Changes in HTML Security introduced in Beta 3
We have made a number of refinements for the Beta 3 release of AIR. Please see below for a summary.
Generic changes somehow related to security
- the “app-resource:” URI scheme has been renamed to “app:”
- “htmlControl” has been renamed to “htmlLoader”
Application Sandbox
Existing code generation techniques that are still restricted in Beta3
- Function constructor
- setTimeout / setInterval used with string parameters instead of function handlers
- "javascript:URL"
- parsing handler attributes (e.g. onclick="myFunction();") inserted with .innerHTML
- parsing script elements inserted with innerHTML (setting non-script static HTML with .innerHTML is fine)
- creating script tags and setting textContent
- loading javavascript files from remote (outside application directory)
- generic use of eval for code generation (* - also check eval section below)
eval()
- eval() function now works on Beta3 with pure JSON strings (object literals and constants only)
- however, no other variant is going to work, such as JSON with callbacks or generic use of eval() for code generation
Changes to when code generation restrictions are applied
- define: parsing time = before and during onLoad event (up to the moment when the last event handler for the "load" finishes)
- during parsing time there are no restrictions applied:
- full featured eval() is allowed
- Function constructor works
- existing markup in page that uses attribute handlers is being parsed and changed into function handlers
- all these restrictions do not apply when your code is being executed in a handler attached for the "load" event with addEventListener; however these restrictions do apply if your code is running inside a function handler triggered from a setTimeout/setInterval call even if the moment of running falls under the parsing time definition.
XMLHttpRequest
- cross domain XMLHttpRequest is still allowed
- asynchronous XMLHttpRequest started during parsing time always finishes after parsing time (see above)
- synchronous XMLHttpRequest started during parsing time that are pointing to remote resources (outside application directory) don't return any data / these are restricted during parsing time.
Non-application Sandbox
No restrictions on runtime code generation
XMLHttpRequest
- cross domain XMLHttpRequest is not allowed by default anymore
- you can re-enable cross-domain XMLHttpRequest by setting the "allowcrossdomainXMLHttpRequest" attribute to the frame/iframe
SandboxBridge
- each sandbox can only modify the functions added from its side, and not from other sandboxes
- e.g.: parentSandboxBridge functions can only be modified by the Application sandbox content (that added those functions) and not from the Non-application sandbox frame or iframe that it was set on
window.open
- window.open is allowed from Non-application sandbox only if it's triggered by a user gesture (press of a button, click on a link)
- the title for the newly opened window consists of "[Application Sandbox Title]:[Title tag in the opened html file]"
AIR Badge

