Cross-scripting van inhoud in verschillende beveiligingssandboxen

Adobe AIR 1.0 of hoger

Het beveiligingsmodel van de runtime isoleert code op basis van de oorsprong. Door cross-scripting van de inhoud in verschillende beveiligingssandboxen kunt u inhoud in een bepaalde beveiligingssandbox toegang bieden tot bepaalde eigenschappen en methoden in een andere sandbox.

AIR-beveiligingssandboxen en JavaScript-code

AIR past een zelfde-oorsprongbeleid toe, dat voorkomt dat code in een bepaald domein kan interageren met inhoud in een ander domein. Alle bestanden worden in een sandbox geplaatst op basis van hun oorsprong. Inhoud in de toepassingssandbox kan normaal gesproken niet het zelfde-oorsprongprincipe schenden en inhoud die van buiten de installatiemap van de toepassing is geladen, cross-scripten. AIR biedt echter een aantal technieken waarmee u cross-scripting kunt toepassen op niet-toepassingsinhoud.

Eén techniek maakt gebruik van frames of iframes om toepassingsinhoud aan een andere beveiligingssandbox toe te wijzen. Pagina's die vanaf de sandboxzone van de toepassing zijn geladen, gedragen zich alsof ze vanaf het externe domein zijn geladen. Voorbeeld: als u toepassingsinhoud toewijst aan het domein example.com , kan die inhoud pagina's cross-scripten die vanaf example.com zijn geladen.

Deze techniek plaatst de toepassingsinhoud in een andere sandbox, zodat code binnen die inhoud niet langer is onderworpen aan de uitvoeringsbeperkingen voor code in geëvalueerde tekenreeksen. U kunt deze techniek van sandboxtoewijzing gebruiken om deze beperkingen te verminderen, zelfs als u geen cross-scripting van externe inhoud hoeft uit te voeren. Inhoud op die manier toewijzen, kan met name interessant zijn als u met een van de vele JavaScript-frameworks werkt, of met bestaande code die is gebaseerd op de evaluatie van tekenreeksen. Neem echter het extra risico in acht dat onvertrouwde inhoud kan worden geïnjecteerd en uitgevoerd als inhoud buiten de toepassingssandbox wordt uitgevoerd. Pas hiervoor de nodige voorzorgsmaatregelen toe.

Anderzijds verliest toepassingsinhoud die aan een andere sandbox is toegewezen, de toegangsrechten voor de API's van AIR, zodat de techniek van sandboxtoewijzing niet kan worden gebruikt om AIR-functionaliteit toegankelijk te maken voor code die buiten de toepassingssandbox wordt uitgevoerd.

Met een andere cross-scriptingtechniek kunt u een interface ( sandboxbridge ) maken tussen inhoud in een niet-toepassingssandbox en het bovenliggende document in de toepassingssandbox. Dankzij deze bridge heeft de onderliggende inhoud toegang tot eigenschappen en methoden die door de bovenliggende inhoud worden gedefinieerd, en omgekeerd. Beide situaties kunnen zich ook tegelijk voordoen.

Ten slotte kunt u ook domeinoverschrijdende XMLHttpRequests uitvoeren vanuit de toepassingssandbox en optioneel vanuit andere sandboxen.

Zie Frame- en iframe-elementen in HTML , HTML-beveiliging in Adobe AIR en XMLHttpRequest-objecten voor meer informatie.

Toepassingsinhoud laden in een niet-toepassingssandbox

Om toepassingsinhoud veilig te cross-scripten met inhoud die van buiten de installatiemap van de toepassing is geladen, kunt u het element frame of iframe gebruiken om toepassingsinhoud in dezelfde beveiligingssandbox als de externe inhoud te laden. Als u geen cross-scripting van de externe inhoud nodig hebt maar toch een pagina van uw toepassing buiten de toepassingssandbox wilt laden, kunt u dezelfde techniek gebruiken, waarbij u http://localhost/ of een andere onschuldige waarde opgeeft als het domein of de oorsprong.

AIR voegt de nieuwe kenmerken sandboxRoot en documentRoot toe aan het element frame, zodat u kunt bepalen of een toepassingsbestand dat in het frame is geladen, moet worden toegewezen aan een niet-toepassingssandbox. Bestanden met een pad onder de URL sandboxRoot worden in plaats daarvan geladen vanuit de map documentRoot . Om veiligheidsredenen wordt de toepassingsinhoud die op die manier wordt geladen, behandeld alsof deze vanaf de URL sandboxRoot is geladen.

De eigenschap sandboxRoot geeft de URL op die moet worden gebruikt om de sandbox en het domein te bepalen waarin de frame-inhoud moet worden geplaatst. Het URL-schema file: , http: of https: moet worden gebruikt. Als u een relatieve URL opgeeft, blijft de inhoud in de toepassingssandbox.

De eigenschap documentRoot bepaalt de map waaruit de frame-inhoud moet worden geladen. Het URL-schema file: , app: of app-storage: moet worden gebruikt.

In het volgende voorbeeld ziet u hoe u inhoud die in de submap sandbox van de toepassing is geïnstalleerd, toewijst voor uitvoering in de externe sandbox en het domein www.example.com :

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

De pagina ui.html kan met behulp van de volgende scripttag een JavaScript-bestand laden vanuit de lokale map sandbox :

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

Deze pagina kan ook inhoud laden vanuit een map op de externe server met bijvoorbeeld de volgende scripttag:

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

De URL sandboxRoot maskeert alle inhoud op dezelfde URL op de externe server. In het vorige voorbeeld hebt u geen toegang tot externe inhoud op www.example.com/local/ (of een van de submappen) omdat AIR de aanvraag omleidt naar de lokale toepassingsmap. Alle aanvragen worden omgeleid, ongeacht of ze afkomstig zijn van paginanavigatie, een XMLHttpRequest of een andere manier om inhoud te laden.

Sandboxbridge-interface instellen

U kunt een sandboxbridge gebruiken als inhoud in de toepassingssandbox toegang moet hebben tot eigenschappen of methoden die zijn gedefinieerd door inhoud in een niet-toepassingssandbox, of als niet-toepassingsinhoud toegang moet hebben tot eigenschappen en methoden die zijn gedefinieerd door inhoud in de toepassingssandbox. Creëer een bridge met de eigenschappen childSandboxBridge en parentSandboxBridge van het object window van een willekeurig onderliggend document.

Onderliggende sandboxbridges creëren

Met de eigenschap childSandboxBridge kan het onderliggende document een interface toegankelijk kan maken voor inhoud in het bovenliggende document. Als u een interface toegankelijk wilt maken, moet u de eigenschap childSandbox instellen op een functie of object in het onderliggende document. Vervolgens hebt u toegang tot het object of de functie vanuit de inhoud van het bovenliggende document. In het volgende voorbeeld ziet u hoe een script dat in een onderliggend document wordt uitgevoerd, een object dat een functie en eigenschap bevat, toegankelijk kan maken voor het bovenliggende document:

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

Als deze onderliggende inhoud wordt geladen in een iframe met de id "child", kunt u de interface vanuit de bovenliggende inhoud benaderen door de eigenschap childSandboxBridge van het frame te lezen:

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

Bovenliggende sandboxbridges creëren

Met de eigenschap parentSandboxBridge kan het bovenliggende document een interface toegankelijk kan maken voor inhoud in een onderliggend document. Als u een interface toegankelijk wilt maken, stelt het bovenliggende document de eigenschap parentSandbox van een onderliggend document in op een functie of object dat in het bovenliggende document wordt gedefinieerd. Vervolgens hebt u toegang tot het object of de functie vanuit de inhoud van het onderliggende document. In het volgende voorbeeld ziet u hoe een script dat in een bovenliggend document wordt uitgevoerd, een object dat een functie bevat, toegankelijk kan maken voor een onderliggend document:

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

Via deze interface kan inhoud in het onderliggende frame tekst opslaan in een bestand met de naam save.txt . Er is echter geen andere toegang tot het bestandssysteem. De onderliggende inhoud kan bijvoorbeeld de functie Save als volgt aanroepen:

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

De toepassingsinhoud moet de kleinst mogelijke interface toegankelijk maken voor andere sandboxen. Niet-toepassingsinhoud moet standaard als onbetrouwbaar worden beschouwd omdat deze inhoud kan blootstaan aan toevallige of kwaadwillige injectie van code. U moet de nodige veiligheidsmaatregelen nemen om misbruik te voorkomen van de interface die u via de bovenliggende sandboxbridge toegankelijk maakt.

Bovenliggende sandboxbridges benaderen tijdens het laden van een pagina

Als een script in een onderliggend document toegang moet hebben tot een bovenliggende sandboxbridge, moet de bridge worden ingesteld voordat het script wordt uitgevoerd. Window-, frame- en iframe-objecten verzenden de gebeurtenis dominitialize nadat een nieuw pagina-DOM is gemaakt maar voordat scripts zijn geparseerd of DOM-elementen zijn toegevoegd. U kunt de gebeurtenis dominitialize gebruiken om de bridge al vroeg in de constructiesequentie van de pagina te creëren, zodat alle scripts in het onderliggende document toegang hebben tot de bridge.

In het volgende voorbeeld ziet u hoe u een bovenliggende sandboxbridge kunt maken als reactie op de gebeurtenis dominitialize die vanuit het onderliggende frame is verzonden:

<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>

Het volgende document, child.html , illustreert hoe onderliggende inhoud de bovenliggende sandboxbridge kan benaderen:

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

Om zeker te zijn dat u naar de gebeurtenis dominitialize in een onderliggend venster luistert en niet naar een frame, moet u de listener aan het nieuwe onderliggende Window-object toevoegen, dat u creëert met de functie window.open() :

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

In dit geval bestaat er geen mogelijkheid om toepassingsinhoud toe te wijzen aan een niet-toepassingssandbox. Deze techniek is alleen nuttig als child.html van buiten de toepassingsmap wordt geladen. U kunt toepassingsinhoud in het venster nog altijd aan een niet-toepassingssandbox toewijzen, maar in dat geval moet u eerst een tussenpagina laden die zelf frames gebruikt om het onderliggende document te laden, en deze pagina toewijzen aan de gewenste sandbox.

Als u de functie createRootWindow() van de klasse HTMLLoader gebruikt om een venster te maken, is het nieuwe venster geen onderliggend element van het document waaruit createRootWindow() wordt opgeroepen. U kunt dus geen sandboxbridge maken tussen het oproepende venster en niet-toepassingsinhoud die in het nieuwe venster is geladen. In plaats daarvan moet u in het nieuwe venster een tussenpagina laden die zelf frames gebruikt om het onderliggende document te laden. U kunt vervolgens de bridge creëren tussen het bovenliggende document van het nieuwe venster en het onderliggende document dat in het frame is geladen.