Cross-Domain Scripting Voodoo

If you’re thinking of hosting your SWFs on a content delivery network to improve the performance of your Flash application, or attempting to load a third-party SWF hosted on another domain into your application, be aware that loading and scripting SWFs from another domain posts a whole set of security issues, namely that of Cross-Domain Scripting. Due to the Flash Player 9’s security sandbox, when you load a SWF from another domain into a SWF hosted on your domain, by default, you will not be able to operate on the child SWF without it specifically granting permission.

Before proceeding with this tutorial, I highly recommend that you to read the Adobe Flash Player 9 Security White Paper. This 51-page document, although thorough in many aspects, unfortunately left out crucial details that one would need in order to successfully perform cross-domain scripting. Another indispensable reference would be Colin Moock’s Essential ActionScript 3.0, in particular, Chapter 19 on Flash Player Security Restrictions and Chapter 28 on Loading External Display Assets.

Let’s get started!

In this tutorial, we will load a SWF named domainB.swf from the domain http://sub.hubflanger.com into a SWF named domainA.swf located at http://hubflanger.com. In the Adobe Flash Player 9 security sandbox, a subdomain is treated like any domain separate from its parent domain, so cross-domain security policies apply. Here, we shall assume that domainA.swf does not have access to any of domainB.swf’s classes during compilation.

View Demo

Download Source Files

1. Setting up your URL policy file

The URL policy file named crossdomain.xml is located, by default, in the root directory of the target server (http://sub.hubflanger.com). This policy file gives the parent SWF permission to load the child SWF.

<?xml version="1.0" encoding="UTF-8" ?>
<cross-domain-policy>
  <allow -access-from domain="*" />
</cross-domain-policy>

2. Examining domainB.fla

In domainB.fla, the document class is linked to the class com.hubflanger.crossdomain.sub.DomainB. In the constructor of the DomainB class, the Security.allowDomain("*"); statement enables scripting of this SWF from another domain (in this case, “*” denotes any domain). The class also has a public method named sayHello() which we will call from domainA.swf when domainB.swf is loaded.

package com.hubflanger.crossdomain.sub
{
  import flash.text.TextField;
  import flash.display.MovieClip;
  import flash.system.Security;

  public class DomainB extends MovieClip
  {
    public var myText1:TextField;

    public function DomainB()
    {
      Security.allowDomain("*");
    }

    public function sayHello( str:String ):void
    {
      myText1.text = str;
    }
  }
}

On the stage, a dynamic textField named myText1 will display a text string passed to the sayHello() method.

In the library panel, a symbol named innerClip is linked to the class com.hubflanger.crossdomain.sub.InnerClip. The InnerClip class has a public method named sayHello() which we will call from domainA.swf as well.

package com.hubflanger.crossdomain.sub
{
  import flash.text.TextField;
  import flash.display.MovieClip;

  public class InnerClip extends MovieClip
  {
    public var myText2:TextField;

    public function InnerClip()
    {
      //
    }

    public function sayInnerHello( str:String ):void
    {
      myText2.text = str;
    }
  }
}

The innerClip symbol also contains a dynamic textField myText2 which will display a text string passed to the sayInnerHello() method.

2. Examining domainA.fla

The domainA.fla is linked to the document class com.hubflanger.crossdomain.DomainA. To import domainB.swf’s classes into domainA.swf’s application domain at runtime, we use a LoaderContext object when issuing the request to load domainB.swf. This makes domainB.swf’s classes directly accessible to domainA.swf.

In the initHandler() listener, we reference the DomainB class by calling the getDefinition() method of the Loader’s applicationDomain property by passing in the classpath com.hubflanger.crossdomain.sub.DomainB. We can then gain access to domainB.swf’s sayHello() method by casting the Loader’s content to the DomainB type.

Similarly, we gain a reference to the InnerClip class and then create an InnerClip instance via this reference. We then call the sayInnerHello() method belonging to this instance.

package com.hubflanger.crossdomain
{
  import flash.display.*;
  import flash.net.*;
  import flash.events.*;
  import flash.system.*;

  public class DomainA extends MovieClip
  {
    public function DomainA()
    {
      var loader:Loader = new Loader();
      loader.contentLoaderInfo.addEventListener( Event.INIT, initHandler );
      loader.contentLoaderInfo.addEventListener( IOErrorEvent.IO_ERROR, ioErrorHandler );
      loader.contentLoaderInfo.addEventListener( SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler );
      addChild(loader);

      var loaderContext:LoaderContext = new LoaderContext( false, ApplicationDomain.currentDomain );
      loaderContext.applicationDomain =  ApplicationDomain.currentDomain;
      loader.load( new URLRequest( "http://sub.hubflanger.com/crossdomain/domainB.swf" ), loaderContext );
    }

    private function initHandler( evt:Event ):void
    {
      var packagePath:String = "com.hubflanger.crossdomain.sub.";

      var appDomain:ApplicationDomain = evt.target.applicationDomain;

      var domainBRef:Class = appDomain.getDefinition( packagePath + "DomainB" )  as  Class;
      var domainB:Object = domainBRef( evt.target.content );
      domainB.sayHello( "Hello World!" );

      var innerClipRef:Class = appDomain.getDefinition( packagePath + "InnerClip" )  as  Class;
      var innerClip:Object = new innerClipRef();
      innerClip.sayInnerHello( "Inner clip says Hello!" );
      addChild( innerClip as MovieClip );
    }

    private function ioErrorHandler( e:IOErrorEvent ):void
    {
      trace( e.text );
    }

    private function securityErrorHandler( e:SecurityErrorEvent ):void
    {
      trace( e.text );
    }
  }
}

That’s it. I hope this tutorial helped to clarify the confusion surrounding the daunting task of Cross-Domain Scripting. Happy coding!

Share/Save/Bookmark

2 Responses to “Cross-Domain Scripting Voodoo”

  1. scott Says:

    great article! :)

  2. sugandha Says:

    wat if my domainB.swf is not self composed. Its an output from pdf2swf and contains a hyperlink that I wish to launch from domainA.swf.
    Kindly mail me :)

Leave a Reply