Cross-Domain Requests in Adobe AIR - Security Series #13
At cf.Objective() this last week, one of the topics of discussion after Samer Sadek's excellent Adobe AIR presentation was about cross-domain restrictions in Adobe AIR applications written with JavaScript. I do not know if this discussion is relevant with AIR applications written with Flex.
As many may know, and if you don't you should read up on this, most browsers implement a "same-origin" policy on JavaScript run within the browser. This means that JavaScript is free to use any resource available from within the domain that it is running, but it cannot use remote resources.
Let's look at an example of this.
I have placed a simple CFC on my web server called RemoteObject.cfc. This CFC contains a single remote method called getRemoteData().
<cfcomponent output="false">
<cffunction name="getRemoteData" access="remote" returntype="struct">
<cfset var myData = StructNew() />
<cfset myData = {fname="Ben", lname="Nadel", status="Awesome"} />
<cfsetting showdebugoutput="false">
<cfreturn myData />
</cffunction>
</cfcomponent>
So we have a method here that will return a struct when called. The struct contains three values fname, lname and status.
Next, I create my JavaScript in my index.htm file to make the remote call:
//Get Remote Data
$(function() {
$.ajax({
url: 'http://12robots.com/RemoteObject.cfc',
data: {'method':'getRemoteData', 'returnformat':'json'},
dataType: 'json',
success: function(data, msg) {
alert(data.FNAME + " " + data.LNAME + " is " + data.STATUS);
},
});
});
Here I am using jQuery to make a simple Ajax request to my remote server as soon as the page is loaded. I am passing in the method name and telling ColdFusion that I would like it to return the struct as JSON. The dataType attribute is telling jQuery that the data being returned is JSON. This allows jQuery to turn it into an object. Finally, on success I am going to create a pop-up of the returned data, except we will never get that far.
When I load my index.htm with this block of JavaScript running automatically, I get this error in FireBug:
Access to restricted URI denied" code: "1012
Anyone who has tried to load data from a remote site with JavaScript is familiar with this error message. This is the browser's enforcement of the single-origin policy. My index.htm is being run from http://localhost:81 and it is trying to receive data from http://12robots.com:80.
There are ways around this restriction, but that is not what we were talking about at cf.Objective(). We were talking about whether or not the same-origin policy exists in an Adobe AIR application.
The simple answer is, No.
Adobe AIR does not enforce the single-origin policy in applications. Functionally, this is a good thing. It means that we can access data from multiple sources and bring that data to a desktop application. Without this functionality, we would be VERY limited in what we could do with our AIR applications.
This also means that the security in an AIR application is a little looser and that we need to make sure, as responsible developers, that we are only pulling data from trusted sources.
So I've taken my index.htm file and places it into an AIR application. I have done nothing else with it. Now, when I run that AIR application, here is the result:







(But at the same time, I'm still waiting for a way to tell the sandbox that, no, I don't access the filesystem so there's no need to freak out the user by telling them that my app wants UNRESTRICTED SYSTEM ACCESS OMG!. Not holding my breath, though.)
As for the file system access, I have been thinking about that one a lot lately. It seems to me that an Adobe AIR app doesn't have any more unrestricted access than any other desktop application. I'm not a desktop developer (outside of AIR) but I would think that any desktop app could have the same "security issue" and that we as computer users really need to think a little more about what we are installing instead of willy-nilly installing any app that looks like it does something cool, whether it is AIR or C++, or whatever.
If I have some time tomorrow, I'll test it with a mxml AIR app.
It was great seeing you at CFO
If I remember correctly, Flex in the browser has a Cross-Site restrictions in place that can be overcome with a cross domain policy file. I'll be curios to see if that is needed for a Flex AIR app as well.
When I ran the swf file of the flex app by itself (outside of the browser), it ran fine with no error. Found this article
http://kb2.adobe.com/cps/142/tn_14213.html
that confirms "Note: This security feature does not affect Flash movies playing in stand-alone projectors."
If only I read the documentation!
Here is the code that I tested:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
<mx:Script>
<![CDATA[
import mx.rpc.events.ResultEvent;
import mx.rpc.events.FaultEvent;
import mx.controls.Alert;
private function handleResult(event:ResultEvent):void {
Alert.show(event.message.body.toString(), "Success");
}
private function handleFault(event:FaultEvent):void {
Alert.show(event.fault.message, "Error");
}
]]>
</mx:Script>
<mx:WebService id="testWS" useProxy="false"
wsdl="http://myserver/cfc/RemoteObject.cfc?wsdl">...;
<mx:operation name="getRemoteData"
result="handleResult(event)"
fault="handleFault(event)" />
</mx:WebService>
<mx:Button x="277" y="169" label="Run Web Server " click="testWS.getRemoteData()" width="235"/>
</mx:Application>
Thanks for looking into that. That is really good to know. I really need to get to learning Flex. It looks like such fun.