Scambio di script per il contenuto presente in sandbox di sicurezza diverse

Adobe AIR 1.0 e versioni successive

Il modello di sicurezza del runtime isola il codice con origini diverse. Grazie allo scambio di script a livello di contenuto tra le diverse sandbox di sicurezza, potete permettere al contenuto in una sandbox di accedere a determinate proprietà e determinati metodi di un'altra sandbox.

Sandbox di sicurezza di AIR e codice JavaScript

AIR implementa il criterio dell'origine comune, al fine di impedire che il codice in un dominio interagisca con il contenuto in altri domini. Tutti i file in una sandbox hanno un'origine comune. In termini generali, il contenuto nella sandbox dell'applicazione non può violare il principio dell'origine comune, né eseguire lo scambio di script per contenuti caricati da un percorso esterno alla directory di installazione dell'applicazione. AIR fornisce tuttavia alcune tecniche che consentono di eseguire lo scambio di script per il contenuto non dell'applicazione.

Una tecnica consiste nell'usare i tag frame e iframe per mappare il contenuto dell'applicazione su una sandbox di sicurezza diversa. Tutte le pagine caricate dall'area interna alla sandbox dell'applicazione si comportano come se fossero caricate da un dominio remoto. Ad esempio, se il contenuto dell'applicazione viene mappato sul dominio example.com , tale contenuto potrà eseguire lo scambio di script per le pagine caricate da example.com.

Poiché in questo modo il contenuto dell'applicazione viene collocato in una sandbox diversa, il codice all'interno del contenuto non sarà più soggetto alle restrizioni riguardanti l'esecuzione di codice nelle stringhe sottoposte a valutazione. Potete usare la tecnica di mappatura della sandbox per aggirare queste restrizioni anche nel caso in cui non dobbiate eseguire lo scambio di script per il contenuto remoto. Questo tipo di mappatura del contenuto è molto utile quando si lavora con uno dei numerosi framework JavaScript o con il codice esistente basato su stringhe di valutazione. Tuttavia, quando il contenuto viene eseguito all'esterno della sandbox dell'applicazione dovete tenere presente (e tutelarvi di conseguenza) che esiste il rischio di introduzione ed esecuzione di eventuale contenuto non affidabile.

Allo stesso tempo, quando il contenuto dell'applicazione viene mappato su una sandbox diversa perde la possibilità di accedere alle API di AIR, pertanto questa tecnica di mappatura non può essere usata per esporre le funzionalità di AIR al codice eseguito all'esterno della sandbox dell'applicazione.

Un'altra tecnica per lo scambio di script è quella che consente di creare un'interfaccia denominata bridge sandbox tra il contenuto di una sandbox non appartenente all'applicazione e il documento principale nella sandbox dell'applicazione. Il bridge consente al contenuto secondario di accedere a proprietà e metodi definiti dal documento principale, e al documento principale di accedere a proprietà e metodi definiti dal documento secondario.

Infine potete anche eseguire richieste XMLHttpRequests tra i domini dalla sandbox dell'applicazione e, facoltativamente, da altre sandbox.

Per ulteriori informazioni, vedete Elementi frame e iframe HTML , Sicurezza HTML in Adobe AIR e Oggetto XMLHttpRequest .

Caricamento del contenuto delle applicazioni in una sandbox non applicazione

Per consentire lo scambio di script del contenuto dell'applicazione dall'esterno della directory di installazione dell'applicazione, potete usare gli elementi frame o iframe per caricare il contenuto dell'applicazione nella stessa sandbox di sicurezza del contenuto esterno. Se non dovete eseguire lo scambio di script di contenuto remoto, ma desiderate comunque caricare una pagina dell'applicazione all'esterno della sandbox dell'applicazione, potete usare la stessa tecnica indicando http://localhost/ , o un altro valore sicuro, come dominio di origine.

AIR aggiunge i nuovi attributi, sandboxRoot e documentRoot , all'elemento frame che consente di stabilire se il file di un'applicazione caricato nel frame deve essere mappato su una sandbox non dell'applicazione. I file che risolvono un percorso sotto l'URL sandboxRoot sono invece caricati dalla directory documentRoot . Per ragioni di sicurezza, il contenuto dell'applicazione caricato in questo modo viene trattato come se fosse realmente caricato dall'URL sandboxRoot .

La proprietà sandboxRoot specifica l'URL da usare per determinare la sandbox e il dominio in cui collocare il contenuto dell'elemento frame. È necessario usare gli schemi URL file: , http: o https: . Se specificate un URL relativo, il contenuto rimane nella sandbox dell'applicazione.

La proprietà documentRoot specifica la directory da cui caricare il contenuto dell'elemento frame. È necessario usare gli schemi URL file: , app: o app-storage: .

Nell'esempio seguente, il contenuto installato nella sottodirectory della sandbox dell'applicazione viene mappato in modo che sia eseguito nella sandbox remota e nel dominio www.example.com :

<iframe 
    src="http://www.example.com/local/ui.html"  
    sandboxRoot="http://www.example.com/local/"  
    documentRoot="app:/sandbox/"> 
</iframe>

La pagina ui.html può caricare un file javascript dalla cartella locale sandbox usando il seguente tag script:

<script src="http://www.example.com/local/ui.js"></script>

Può inoltre caricare contenuto da una directory del server remoto usando un tag script simile al seguente:

<script src="http://www.example.com/remote/remote.js"></script>

L'URL sandboxRoot nasconderà tutto il contenuto con lo stesso URL sul server remoto. Con l'esempio precedente non potete accedere al contenuto remoto presente in www.example.com/local/ (e relative sottodirectory) in quanto AIR rimappa la richiesta sulla directory locale dell'applicazione. Le richieste vengono rimappate sia che provengano dalla navigazione della pagina, da un oggetto XMLHttpRequest o da altri strumenti di caricamento del contenuto.

Impostazione dell'interfaccia per un bridge sandbox

Potete usare un bridge sandbox quando il contenuto nella sandbox dell'applicazione deve accedere a proprietà o metodi definiti dal contenuto in una sandbox non dell'applicazione, o quando il contenuto di una sandbox non dell'applicazione deve accedere a proprietà o metodi definiti dal contenuto nella sandbox dell'applicazione. Create un bridge con le proprietà childSandboxBridge e parentSandboxBridge dell'oggetto window di un documento secondario qualunque.

Impostazione di un bridge sandbox secondario

La proprietà childSandboxBridge consente al documento secondario di esporre un'interfaccia al contenuto nel documento principale. Per esporre un'interfaccia, impostate la proprietà childSandbox su una funzione o un oggetto nel documento secondario. Potete quindi accedere all'oggetto o alla funzione dal contenuto nel documento principale. L'esempio seguente mostra come uno script eseguito in un documento secondario possa esporre un oggetto contenente una funzione e una proprietà al documento principale:

var interface = {}; 
interface.calculatePrice = function(){ 
    return ".45 cents"; 
} 
interface.storeID = "abc" 
window.childSandboxBridge = interface;

Se il contenuto secondario è stato caricato in un elemento iframe e associato a un id “child”, potete accedere all'interfaccia tramite il contenuto principale leggendo la proprietà childSandboxBridge dell'elemento frame:

var childInterface = document.getElementById("child").contentWindow.childSandboxBridge; 
air.trace(childInterface.calculatePrice()); //traces ".45 cents" 
air.trace(childInterface.storeID)); //traces "abc"

Impostazione di un bridge sandbox principale

La proprietà parentSandboxBridge consente al documento principale di esporre un'interfaccia al contenuto nel documento secondario. Per esporre un'interfaccia, il documento principale imposta la proprietà parentSandbox del documento secondario su una funzione o un oggetto definiti nel documento principale. A questo punto potete accedere all'oggetto o alla funzione dal contenuto nel documento secondario. L'esempio seguente mostra come uno script eseguito in un frame principale possa esporre un oggetto contenente una funzione a un documento secondario:

var interface = {}; 
interface.save = function(text){ 
    var saveFile = air.File("app-storage:/save.txt"); 
    //write text to file 
} 
document.getElementById("child").contentWindow.parentSandboxBridge = interface;

Usando questa interfaccia, il contenuto nel frame secondario potrebbe salvare il testo in un file denominato save.txt , ma non avrebbe alcun altro tipo di accesso al file system. Il contenuto secondario può chiamare la funzione save nel seguente modo:

var textToSave = "A string."; 
window.parentSandboxBridge.save(textToSave);

Il contenuto dell'applicazione deve esporre alle altre sandbox un'interfaccia il più ridotta possibile. Il contenuto non dell'applicazione deve essere considerato non affidabile, in quanto può essere soggetto all'inserimento accidentale o deliberato di codice dannoso. È necessario salvaguardarsi in modo adeguato per prevenire qualunque abuso dell'interfaccia esposta con il bridge sandbox principale.

Impostazione di un bridge sandbox principale durante il caricamento della pagina

Affinché lo script di un documento secondario possa accedere a un bridge sandbox secondario, il bridge deve essere impostato prima dell'esecuzione dello script. Gli oggetti Window, frame e iframe inviano un evento dominitialize quando viene creato un modello DOM per una nuova pagina, ma prima dell'analisi di qualunque script o dell'aggiunta degli elementi DOM. Potete usare l'evento dominitialize per impostare il bridge nelle fasi iniziali della sequenza di creazione della pagina, così da permettere a tutti gli script del documento secondario di accedervi.

Il seguente esempio mostra come creare un bridge sandbox principale in risposta a un evento dominitialize inviato dal frame secondario:

<html> 
<head> 
<script> 
var bridgeInterface = {}; 
bridgeInterface.testProperty = "Bridge engaged"; 
function engageBridge(){ 
    document.getElementById("sandbox").contentWindow.parentSandboxBridge = bridgeInterface; 
} 
</script> 
</head> 
<body> 
<iframe id="sandbox" 
            src="http://www.example.com/air/child.html"  
            documentRoot="app:/" 
            sandboxRoot="http://www.example.com/air/" 
            ondominitialize="engageBridge()"/> 
</body> 
</html>

Nel seguente documento child.html il contenuto secondario può accedere al bridge sandbox principale:

<html> 
    <head> 
        <script> 
            document.write(window.parentSandboxBridge.testProperty); 
        </script>   
    </head>   
    <body></body> 
</html>

Per intercettare l'evento dominitialize in una finestra secondaria, anziché in un frame, dovete aggiungere il listener al nuovo oggetto secondario window creato dalla funzione window.open() :

var childWindow = window.open(); 
childWindow.addEventListener("dominitialize", engageBridge()); 
childWindow.document.location = "http://www.example.com/air/child.html";

In questo caso non vi è modo di mappare il contenuto dell'applicazione su una sandbox di sicurezza non dell'applicazione. Questa tecnica è utile solo nel caso in cui il file child.html venga caricato da un percorso esterno alla directory dell'applicazione. Potete sempre mappare il contenuto dell'applicazione presente nella finestra su una sandbox non dell'applicazione, ma prima dovrete caricare una pagina intermedia, anch'essa basata sui frame, per caricare il documento secondario e mapparlo sulla sandbox desiderata.

Se usate la funzione createRootWindow() della classe HTMLLoader per creare una finestra, la nuova finestra non sarà secondaria rispetto al documento da cui viene chiamata la funzione createRootWindow() . Pertanto, non potete creare un bridge sandbox tra la finestra chiamante e il contenuto non dell'applicazione caricato nella nuova finestra. Dovrete invece caricare una pagina intermedia nella nuova finestra, anch'essa basata sui frame, per caricare il documento secondario. Potete impostare il bridge tra il documento principale della nuova finestra e il documento secondario caricato nel frame.