異なるドメインのコンテンツ間のスクリプト作成

Adobe AIR 1.0 およびそれ以降

AIR アプリケーションは、インストール時に特殊な権限を付与されます。アプリケーションに含まれていないリモートファイルやローカルファイルなどの他のコンテンツに同じ権限情報が流出しないようにすることが重要です。

AIR サンドボックスブリッジについて

通常、他のドメインのコンテンツで、他のドメインのスクリプトを呼び出すことはできません。AIR アプリケーションで権限が与えられている情報や制御が誤って流出しないようにするために、 アプリケーション セキュリティサンドボックス内のコンテンツ(アプリケーションと共にインストールされるコンテンツ)に次の制限が適用されます。

  • アプリケーションセキュリティサンドボックス内のコードでは、 Security.allowDomain() メソッドを呼び出して他のサンドボックスへのクロススクリプトを実行できません。アプリケーションセキュリティサンドボックスからこのメソッドを呼び出すと、エラーがスローされます。

  • LoaderContext.securityDomain または LoaderContext.applicationDomain プロパティを設定して、非アプリケーションコンテンツをアプリケーションサンドボックスに読み込むことはできません。

メインの AIR アプリケーションが、リモートドメインのコンテンツに対してメインの AIR アプリケーション内のスクリプトへの制御付きアクセス権を持っていることを要求する場合や、その逆の場合もあります。これを実現するために、ランタイムには、2 つのサンドボックス間のゲートウェイとして機能する、 サンドボックスブリッジ メカニズムがあります。サンドボックスブリッジを使用すると、リモートサンドボックスとアプリケーションセキュリティサンドボックス間で明示的な操作を実行できます。

サンドボックスブリッジは、読み込まれる側のスクリプトと読み込む側のスクリプトの両方がアクセスできる 2 つのオブジェクトを公開します。

  • parentSandboxBridge オブジェクトを使用すると、読み込む側のコンテンツは読み込まれる側のコンテンツのスクリプトにプロパティと関数を公開できます。

  • childSandboxBridge オブジェクトを使用すると、読み込まれる側のコンテンツが読み込む側のコンテンツのスクリプトにプロパティと関数を公開できます。

サンドボックスブリッジによって公開されるオブジェクトは、参照ではなく値によって受け渡されます。すべてのデータは直列化されます。つまり、ブリッジの片側で公開されたオブジェクトはもう一方の側で設定できず、公開されたそのオブジェクトはすべて型指定されません。また、公開できるのは単純なオブジェクトと関数だけで、複雑なオブジェクトは公開できません。

子コンテンツがオブジェクトを parentSandboxBridge オブジェクトに設定しようとすると、ランタイムによって SecurityError 例外がスローされます。同様に、親コンテンツがオブジェクトを childSandboxBridge オブジェクトに設定しようとすると、ランタイムによって SecurityError 例外がスローされます。

サンドボックスブリッジの例(SWF)

AIR ミュージックストアアプリケーションでは、リモート SWF ファイルでアルバムの価格をブロードキャストできるようにする必要がありますが、リモート SWF ファイルでその価格が販売価格かどうかを公開しないようにする必要があるとします。この場合、StoreAPI クラスのメソッドを使用して、価格を取得しても販売価格は公開されないようにします。次に、この StoreAPI クラスのインスタンスが、リモート SWF を読み込む Loader オブジェクトの LoaderInfo オブジェクトの parentSandboxBridge プロパティに割り当てられます。

AIR ミュージックストアのコードを次に示します。

<?xml version="1.0" encoding="utf-8"?> 
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" title="Music Store" creationComplete="initApp()"> 
    <mx:Script> 
        import flash.display.Loader; 
        import flash.net.URLRequest; 
     
        private var child:Loader; 
        private var isSale:Boolean = false; 
         
        private function initApp():void { 
            var request:URLRequest =  
                    new URLRequest("http://[www.yourdomain.com]/PriceQuoter.swf") 
 
            child = new Loader(); 
            child.contentLoaderInfo.parentSandboxBridge = new StoreAPI(this); 
            child.load(request); 
            container.addChild(child); 
        } 
        public function getRegularAlbumPrice():String { 
            return "$11.99"; 
        } 
        public function getSaleAlbumPrice():String { 
            return "$9.99"; 
        } 
        public function getAlbumPrice():String { 
            if(isSale) { 
                return getSaleAlbumPrice(); 
            } 
            else { 
                return getRegularAlbumPrice();     
            } 
        } 
    </mx:Script> 
    <mx:UIComponent id="container" /> 
</mx:WindowedApplication> 

StoreAPI オブジェクトはメインアプリケーションを呼び出して通常のアルバム価格を取得しますが、 getSaleAlbumPrice() メソッドが呼び出されると、「Not available」を返します。次のコードでは、StoreAPI クラスを定義します。

public class StoreAPI 
{ 
    private static var musicStore:Object; 
     
    public function StoreAPI(musicStore:Object) 
    { 
        this.musicStore = musicStore; 
    } 
 
    public function getRegularAlbumPrice():String { 
        return musicStore.getRegularAlbumPrice(); 
    } 
     
    public function getSaleAlbumPrice():String { 
        return "Not available"; 
    } 
     
    public function getAlbumPrice():String { 
        return musicStore.getRegularAlbumPrice();     
    } 
}

次のコードは、ストアの価格を報告しても、販売価格は報告できない PriceQuoter SWF ファイルの例を表しています。

package 
{ 
    import flash.display.Sprite; 
    import flash.system.Security; 
    import flash.text.*; 
     
    public class PriceQuoter extends Sprite 
    { 
        private var storeRequester:Object; 
         
        public function PriceQuoter() { 
            trace("Initializing child SWF"); 
            trace("Child sandbox: " + Security.sandboxType); 
            storeRequester = loaderInfo.parentSandboxBridge; 
             
            var tf:TextField = new TextField(); 
            tf.autoSize = TextFieldAutoSize.LEFT; 
            addChild(tf); 
             
            tf.appendText("Store price of album is: " + storeRequester.getAlbumPrice()); 
            tf.appendText("\n"); 
            tf.appendText("Sale price of album is: " + storeRequester.getSaleAlbumPrice()); 
        } 
    } 
}

サンドボックスブリッジの例(HTML)

HTML コンテンツで、 parentSandboxBridge プロパティと childSandboxBridge プロパティが子ドキュメントの JavaScript の window オブジェクトに追加されます。HTML コンテンツでのブリッジ関数の設定方法の例については、 サンドボックスブリッジインターフェイスの設定 を参照してください。

API 公開の制限

サンドボックスブリッジを公開する場合は、高度なレベルの API を公開してそれらが悪用されない程度まで制限することが重要です。ブリッジ実装を呼び出しているコンテンツは(コードの挿入などにより)改ざんされる可能性があることに注意してください。例えば、 readFile(path:String) メソッド(任意のファイルのコンテンツを読み込むメソッド)をブリッジを通じて公開すると、悪用されやすくなります。この場合はパスを取得せずに特定のファイルを読み込む readApplicationSetting() API を公開する方が安全です。アプリケーションの一部が改ざんされた後でもアプリケーションで実行できる、より意味のある方法によって、損害の広がりを抑えることができます。