Every Flash or Flex developer who has had to access remote resources has come across a crossdomain.xml policy file at some point. This article takes a look at what these policy files are, how they work and how you can create one for yourself.
Example
Let’s take a look at an example of what we’re talking about:
What’s so special about this? Well, the SWF is loading the smiley picture from http://mytestgae.appspot.com/images/smiley.jpg, not from the Activetuts+ domain. Without a cross domain policy file, trying to load the image would trigger a SecurityError.
What is a Cross Domain Policy File?
The security model known as the "same origin" policy, implemented by most modern web browsers, prevents some types of content from being accessed or modified if the file exists on another domain. It’s not a hard and fast rule; HTML pages will happily display images and HTML from pages on other domains. But for JavaScript the same origin policy prevents a document or script loaded from one origin from getting or setting properties of a document from another.
Flash includes a similar security policy which generally prevents a Flash application from accessing data that is hosted on a remote domain. However there are many circumstances where it is not only useful but expected that resources will be accessed remotely. An online photo album would find itself limited if external applications could not download its images. It would also be silly if a web service didn’t allow outside applications to interact with it.
For this reason it’s possible to create an XML file, called crossdomain.xml, that specifies how data on a domain can be accessed by a Flash application hosted on a remote domain. For the most part these policy files are quite simple, but there are a few details that it is useful to be aware of.
If you are hosting content that you want to be accessed by external Flash applications, you will need to create a crossdomain.xml file. Let’s start by taking a look at a basic example.
Step 1: A Basic crossdomain.xml File
Here is a very simple crossdomain.xml file. When this file is hosted on the root of your domain it permits external Flash applications access to all the resources on your domain.
<?xml version="1.0"?> <cross-domain-policy> <allow-access-from domain="*" /> </cross-domain-policy>
The policy file contains a single <cross-domain-policy> tag. Inside this you can have zero or more <allow-access-from> tags. Each <allow-access-from> tag can be used to define a domain or IP address from which a Flash application can access the local resources. The attribute domain="*" specifies that all domains have access. This is thanks to the asterisk wildcard, which is used here to match all domains and IP addresses.
For most situations this "allow all" policy file is sufficient. It grants Flash applications access to all pubic resources, while any security you have in place (like password protected pages) will still prevent Flash applications from accessing sensitive data.
(Note that you cannot put a crossdomain.xml file on your domain that will allow SWFs also on your domain to access remote files on another domain!)
Step 2: Specified Domains
If you do not want to allow global access to your public resources, the domain attribute in the <allow-access-from> tag can be used to grant access to specific domains.
You can specify a domain in its entirety. The example below will give access to Flash applications hosted in the www.example.com domain.
<allow-access-from domain="www.example.com" />
You can use the asterisk wildcard to match those domains that end with the given suffix. Here we grant access to Flash applications on the domains example.com, www.example.com, whatever.example.com etc.
<allow-access-from domain="*.example.com" />
Step 3: Specified IP Addresses
You can specify access by IP address just as you can grant access to Flash applications hosted on specified domains. The same tag and attributes are used, except in this case you use an IP address:
<allow-access-from domain="123.456.789.123" />
Step 4: Working with HTTPS
By default a Flash application hosted on an HTTPS server can only access resources on remote HTTPS servers. But given the overhead that HTTPS can add to a server you may not want to use it. In this case setting the secure attribute to false will allow a Flash application on an HTTPS server to access data from an HTTP server.
<allow-access-from domain="*" secure="false"/>
Step 5: Remote Flash Applications
So what if you don’t want remote Flash applications accessing your data? You can either create a crossdomain.xml file that does not include any <allow-access-from> tags:
<?xml version="1.0"?> <cross-domain-policy> </cross-domain-policy>
Or you can simply not have a crossdomain.xml file at all.
Step 6: Granular Control of Subdirectories
A cross domain policy file will control access to the directory it resides in, and all the subdirectories beneath it. This is how placing a "allow all" policy file at your domain root allows access to your entire domain. But there may be situations where you want to only allow access to a certain subdirectory.
With the latest versions of the Flash Player this requires two XML files. First you need to place a crossdomain.xml file in the root of your domain that allows Flash to process additional cross domain policy files within the subdirectories. This is done with the <site-control> tag. In the example below we set the permitted-cross-domain-policies attribute to all, which means that the cross domain policy files that may exist in the subdirectories will be processed. This behavior is a change in Flash Player 9 Update 3 and up. Previously policy files in subdirectories were processed by default without having to set the permitted-cross-domain-policies attribute.
Note that we have not added any <allow-access-from> tags, which means in the absence of an additional crossdomain.xml files in the subdirectories, remote Flash applications will not have access to the resources on this server.
You can find out more about the meta policy options in this article.
<?xml version="1.0"?> <cross-domain-policy> <site-control permitted-cross-domain-policies="all"/> </cross-domain-policy>
Next, you place a crossdomain.xml file in the subdirectory you wish to control.
To see an example of this in action check out this file. This policy file, in the root of the http://mytestgae.appspot.com/ domain, uses the <site-control> tag to delegate control to any crossdomain.xml files that may exist in the subdirectories. Then this policy file in the /images/ subdirectory grants full access to the directory and any subdirectory beneath it. So a remote Flash application could access the smiley face image in the images directory like so:
<?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" width="550" height="400" applicationComplete="onAppComplete()"> <mx:Image id="image" scaleContent="true" horizontalCenter="0" verticalCenter="0"/> <mx:Script> <![CDATA[ private function onAppComplete():void { Security.loadPolicyFile("http://mytestgae.appspot.com/images/crossdomain.xml"); var loaderContext:LoaderContext = new LoaderContext(); loaderContext.checkPolicyFile = true; var loader:Loader = new Loader(); loader.contentLoaderInfo.addEventListener( Event.COMPLETE, function(event:Event):void { image.source = event.currentTarget.content; } ); loader.load(new URLRequest(encodeURI("http://mytestgae.appspot.com/images/smiley.jpg")), loaderContext); } ]]> </mx:Script> </mx:Application>
However, access to the smiley face image in the /images-restricted/ directory is not permitted because there is no crossdomain.xml file in the images-restricted directory to override the (lack of) access granted by the crossdomain.xml file in the root of the domain. Running the code below will result in an exception being thrown:
<?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" width="550" height="400" applicationComplete="onAppComplete()"> <mx:Image id="image" scaleContent="true" horizontalCenter="0" verticalCenter="0"/> <mx:Script> <![CDATA[ private function onAppComplete():void { var loaderContext:LoaderContext = new LoaderContext(); loaderContext.checkPolicyFile = true; var loader:Loader = new Loader(); loader.contentLoaderInfo.addEventListener( Event.COMPLETE, function(event:Event):void { image.source = event.currentTarget.content; } ); loader.load(new URLRequest(encodeURI("http://mytestgae.appspot.com/images-restricted/smiley.jpg")), loaderContext); } ]]> </mx:Script> </mx:Application>
The exception reads:
SecurityError: Error #2123: Security sandbox violation: LoaderInfo.content: file:///D|/CrossDomain.swf cannot access http://mytestgae.appspot.com/images-restricted/smiley.jpg. No policy files granted access.
at flash.display::LoaderInfo/get content()
at MethodInfo-635()
Step 7: Cross Domain Policy vs. Firewall
So from the above information it looks like cross domain policy files can be used to effectively restrict access to Flash applications not hosted on your own domain. While that is true, you should not rely on a cross domain policy file to restrict access to sensitive information. While Flash may respect a crossdomain.xml policy file, other platforms like PHP won’t. Do a search for PHP Flash Proxy to see what I mean. By using a proxy it’s possible to get access to any publicly available data regardless of the existence of cross domain policy files. And you don’t even have to pay for a PHP server – as I will demonstrate in a future article, Google App Engine can be used as a proxy with no up front costs.
The bottom line is that cross domain policy files provide a way to selectively grant access to local resources by remote Flash applications, but only if everyone plays by the rules. If you want to ensure that your private data stays private, there is no substitute for a firewall.
Conclusion
Dealing with cross domain policy files doesn’t need to be complicated. Once you understand the basics of how they work it is quite easy to grant or restrict access to your data by remote Flash applications. Just be aware that they are not as secure as they might initially seem.
I hope you liked this Quick Tip, thanks for reading!