Sécurité HTML dans Adobe AIR

Adobe AIR 1.0 et les versions ultérieures

Cette section décrit l’architecture de la sécurité HTML dans AIR, ainsi que l’utilisation d’iframes, d’images et du pont de sandbox pour configurer les applications HTML et sécuriser l’intégration de contenu HTML à des applications SWF.

Le moteur d’exécution applique des règles et fournit des mécanismes pour compenser des vulnérabilités de sécurité possibles dans HTML et JavaScript. Les mêmes règles s’appliquent que votre application soit rédigée principalement en JavaScript ou que vous chargiez le contenu HTML et JavaScript dans une application basée sur SWF. Les contenus du sandbox de l’application et du sandbox de sécurité hors application possèdent des privilèges différents. Lorsque vous chargez un contenu dans une iframe ou une image, le moteur d’exécution fournit un mécanisme pont de sandbox sécurisé qui permet au contenu de l’image ou de l’iframe de communiquer de façon sûre avec le contenu du sandbox de sécurité de l’application.

Le SDK d’AIR intègre trois classes de rendu du contenu HTML.

La classe HTMLLoader assure une intégration étroite entre le code JavaScript et les API d’AIR.

La classe StageWebView est une classe de rendu HTML et son intégration à l’application AIR hôte est extrêmement réduite. Le contenu chargé par la classe StageWebView n’est jamais placé dans le sandbox de sécurité de l’application et il lui est impossible d’accéder aux données ou d’appeler des fonctions dans l’application AIR hôte. Sur les plates-formes de poste de travail, la classe StageWebView fait appel au moteur HTML AIR intégré, basé sur Webkit, qui est également utilisé par la classe HTMLLoader. Sur les plates-formes mobiles, elle fait appel au contrôle HTML fourni par le système d’exploitation. Par conséquent, sur les plates-formes mobiles, la classe StageWebView est soumise aux mêmes considérations de sécurité et souffre des mêmes vulnérabilités que le navigateur Web du système.

La classe TextField peut afficher des chaînes de texte HTML. Il est impossible d’exécuter du code JavaScript, mais le texte peut inclure des liens et des images chargées en externe.

Pour plus d’informations, voir la section Contournement des erreurs JavaScript liées à la sécurité .

Aperçu de la configuration de vos applications à base d’HTML

Les images et iframes fournissent une structure adéquate pour l’organisation du contenu HTML dans AIR. Les images fournissent des moyens qui permettent à la fois de maintenir la persistance des données et pour travailler de façon sécurisée avec du contenu distant.

Comme HTML dans AIR conserve son organisation normale, basée sur des pages, l’environnement HTML est intégralement actualisé si l’image supérieure de votre contenu HTML « navigue » dans une page différente. Vous pouvez utiliser des images et des iframes pour maintenir la persistance des données dans AIR pratiquement de la même façon que vous le feriez pour une application Web qui s’exécuterait dans un navigateur. Définissez les principaux objets de votre application dans l’image supérieure et ils persisteront aussi longtemps que vous n’autoriserez pas l’image à naviguer dans une nouvelle page. Utilisez des images ou des iframes enfant pour charger et afficher des parties transitoires de l’application. Il existe plusieurs façons de maintenir la persistance des données, en plus des images ou bien à leur place. Par exemple, des cookies, des objets locaux partagés, l’emplacement de stockage des fichiers locaux, celui des fichiers chiffrés et celui des bases de données locales.

Comme HTML dans AIR conserve sa frontière normale et imprécise entre le code exécutable et les données, AIR place le contenu de l’image supérieure de l’environnement HTML dans le sandbox de l’application. Après l’événement load de la page, AIR restreint toutes les opérations, telles que eval() , susceptibles de convertir une chaîne de texte en un objet exécutable. Cette restriction est imposée même lorsqu’une application ne charge pas du contenu distant. Pour que du contenu HTML distant puissent exécuter ces opérations restreintes, vous devez utiliser des images ou des iframes pour placer le contenu dans un sandbox hors application. (L’exécution de contenu dans une image enfant affectée à un sandbox peut s’avérer nécessaire lorsque vous utilisez des structures d’application JavaScript qui reposent sur la fonction eval() .) Pour un répertoire complet des restrictions relatives à JavaScript dans le sandbox de l’application, voir la section Restrictions relatives au code pour un contenu dans des sandbox différents .

Comme HTML dans AIR conserve sa capacité à charger du contenu distant et possiblement non sécurisé, AIR applique une politique de « même origine » qui empêche le contenu d’un domaine d’interagir avec celui de l’autre. Pour permettre une interaction entre contenu de l’application et contenu d’un autre domaine, vous pouvez configurer un pont qui servira d’interface entre une image parent et une image enfant.

Configuration d’un rapport de sandbox parent-enfant

AIR ajoute les attributs sandboxRoot et documentRoot aux éléments image et iframe de HTML. Ces attributs vous permettent de traiter le contenu de l’application comme s’il provenait d’un autre domaine :

Attribut

Description

sandboxRoot

L’URL à utiliser pour déterminer le sandbox et le domaine dans lesquels placer le contenu de l’image. Les modèles d’URL file: , http: ou https: doivent être utilisés.

documentRoot

L’URL à partir de laquelle il faut charger le contenu de l’image. Les modèles d’URL app: , http: ou app-storage: doivent être utilisés.

L’exemple ci-dessous mappe le contenu installé dans le sous-répertoire du sandbox de l’application qui doit s’exécuter dans le sandbox distant et le domaine www.example.com :

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

Configuration d’un pont entre images parent et enfant dans des sandbox ou des domaines différents

AIR ajoute les propriétés childSandboxBridge et parentSandboxBridge à l’objet window de toute image enfant. Ces propriétés vous permettent de définir des ponts qui serviront d’interfaces entre une image parent et une image enfant. Chaque pont ne va que dans une seule direction :

childSandboxBridge : la propriété childSandboxBridge permet à l’image enfant de présenter une interface au contenu dans l’image parent. Pour présenter une interface, vous définissez la propriété childSandbox sur une fonction ou un objet dans l’image enfant. Vous pouvez alors accéder à l’objet ou à la fonction à partir du contenu dans l’image parent. L’exemple ci-dessous montre comment un script qui s’exécute dans une image enfant peut présenter un objet contenant une fonction ou une propriété à son parent :

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

Si ce contenu enfant est dans une iframe affectée d’une id child , vous pouvez accéder à l’interface à partir du contenu parent en lisant la propriété childSandboxBridge de l’image :

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

parentSandboxBridge : la propriété parentSandboxBridge permet à l’image parent de présenter une interface au contenu dans l’image enfant. Pour présenter une interface, vous définissez la propriété parentSandbox de l’image enfant sur une fonction ou un object dans l’image parent. Vous pouvez alors accéder à l’objet ou à la fonction à partir du contenu dans l’image enfant. L’exemple ci-dessous montre comment un script qui s’exécute dans l’image parent peut présenter un objet contenant une fonction save à un enfant :

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

Avec cette interface, le contenu de l’image enfant pourrait enregistrer du texte dans un fichier appelé save.txt. Toutefois, il ne pourrait avoir aucun autre accès au système de fichiers. En règle générale, le contenu de l’application devrait présenter l’interface la plus étroite possible aux autres sandbox. Le contenu enfant pourrait appeler la fonction save comme suit :

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

Si le contenu enfant tente de définir une propriété de l’objet parentSandboxBridge , le moteur d’exécution renvoie une exception SecurityError. Si le contenu parent tente de définir une propriété de l’objet childSandboxBridge , le moteur d’exécution renvoie une exception SecurityError.

Restrictions relatives au code pour un contenu dans des sandbox différents

Comme nous l’avons vu dans l’introduction à cette rubrique, Sécurité HTML dans Adobe AIR , le moteur d’exécution applique les règles et fournit des mécanismes pour compenser les vulnérabilités de sécurité possibles dans HTML et JavaScript. La présente rubrique répertorie ces restrictions. Si le code tente d’appeler ces interfaces de programmation réservées, le moteur d’exécution renvoie une erreur accompagnée du message « Violation des règles de sécurité dans le sandbox de sécurité de l’application par le moteur d’exécution d’Adobe AIR sur du code JavaScript ».

Pour plus d’informations, voir la section Contournement des erreurs JavaScript liées à la sécurité .

Restrictions relatives à l’utilisation de la fonction eval() de JavaScript et de techniques similaires

Pour le contenu HTML dans le sandbox de sécurité de l’application, il existe des limites dans l’utilisation des interfaces de programmation susceptibles de transformer dynamiquement les chaînes en code exécutable après le chargement de ce code (après que l’événement onload de l’élément body a été distribué et que l’exécution de la fonction du gestionnaire onload est terminée). Ceci empêche l’application d’injecter (et d’exécuter) du code par inadvertance à partir de sources non-applicatives, comme des domaines du réseau potentiellement non sécurisés.

Par exemple, si votre application utilise des données de chaîne à partir d’une source distante pour écrire dans la propriété innerHTML d’un élément DOM, la chaîne pourrait inclure du code exécutable (JavaScript) et susceptible d’exécuter des opérations non sécurisées. Toutefois, tant que le contenu est en cours de chargement, il n’y a pas de risque que des chaînes distantes soient insérées dans le DOM.

L’utilisation de la fonction eval() de JavaScript constitue une restriction. Dès que le code du sandbox de l’application est chargé et après le traitement du gestionnaire d’événement onload, vous ne pouvez utiliser la fonction eval() que dans certaines conditions. Les règles suivantes s’appliquent dans l’utilisation de la fonction eval() après le chargement du code à partir du sandbox de sécurité de l’application :

  • Les expressions contenant des littéraux sont autorisées. Exemple :

    eval("null"); 
    eval("3 + .14"); 
    eval("'foo'");
  • Les littéraux d’objet sont autorisés, comme dans les cas décrits ci-dessous :

    { prop1: val1, prop2: val2 }
  • Les littéraux d’objet de lecture et de définition (getter/setter) sont interdits comme dans les exemples ci-dessous :

    { get prop1() { ... }, set prop1(v) { ... } }
  • Les littéraux de tableau sont autorisés, comme dans les cas décrits ci-dessous :

    [ val1, val2, val3 ]
  • Les expressions impliquant des lectures de propriété sont interdites comme dans ce qui suit :

    a.b.c
  • Le lancement de fonctions est interdit .

  • Les définitions de fonctions sont interdites .

  • Le paramétrage de toute propriété est interdit .

  • Les littéraux de fonctions sont interdits .

Toutefois, au cours du chargement du code, avant l’événement onload et au cours de l’exécution de la fonction du gestionnaire d’événement onload , ces restrictions ne s’appliquent pas au contenu du sandbox de sécurité de l’application.

Par exemple, après le chargement du code, l’exécution du code ci-dessous dans le moteur d’exécution renvoie une exception.

eval("alert(44)"); 
eval("myFunction(44)"); 
eval("NativeApplication.applicationID");

Un code généré dynamiquement, comme celui qui est produit par l’appel de la fonction eval() , présenterait un risque pour la sécurité s’il était autorisé au sein du sandbox de l’application. Par exemple, une application peut exécuter par inadvertance une chaîne chargée à partir d’un domaine de réseau et celle-ci peut contenir du code malveillant. Par exemple, il peut s’agir de code conçu pour la suppression ou la modification de fichiers dans l’ordinateur de l’utilisateur. Ou bien encore de code qui renvoie à un domaine de réseau non approuvé une copie du contenu d’un fichier local.

Vous trouverez ci-dessous des façons de générer du code dynamique :

  • Appel de la fonction eval() .

  • Utilisation des propriétés innerHTML ou des fonctions DOM pour insérer des balises de script qui chargent un script hors du répertoire de l’application.

  • Utilisation des propriétés innerHTML ou des fonctions DOM pour insérer des balises de script qui possèdent du code incorporé (plutôt que de charger un script au moyen de l’attribut src ).

  • Paramétrage de l’attribut src pour qu’une balise script charge un fichier JavaScript qui est hors du répertoire de l’application.

  • Utilisation du modèle d’URL de JavaScript comme dans ( href="javascript:alert('Test')" ).

  • Utilisation de la fonction setInterval() ou setTimout() , où le premier paramètre (qui définit la fonction pour qu’elle s’exécute de façon asynchrone) est une chaîne (à évaluer) plutôt qu’un nom de fonction (comme dans setTimeout('x = 4', 1000) ).

  • Appel de document.write() ou de document.writeln() .

Le code dans le sandbox de sécurité de l’application ne peut utiliser ces méthodes au cours du chargement du contenu.

Ces restrictions n’empêchent pas l’utilisation d’ eval() avec des littéraux d’objet JSON. Ceci permet au contenu de votre application de travailler avec la bibliothèque JavaScript de JSON. Il vous est néanmoins interdit d’utiliser du code JSON surchargé (avec des gestionnaires d’événement).

Pour d’autres structures Ajax et bibliothèques de code JavaScript, assurez-vous que le code de la structure ou de la bibliothèque fonctionne sur du code généré dynamiquement, dans le cadre de ces restrictions. Si ce n’est pas le cas, placez tout contenu qui utilise la structure ou la bibliothèque dans un sandbox de sécurité hors application. Pour plus d’informations, voir Restrictions associées au contenu JavaScript dans AIR et Programmation entre contenu d’application et contenu hors application . Adobe maintient un répertoire de structures Ajax, reconnues pour leur prise en charge du sandbox de sécurité de l’application, à l’adresse http://www.adobe.com/products/air/develop/ajax/features/ .

Contrairement au contenu du sandbox de sécurité de l’application, celui de JavaScript dans un sandbox de sécurité hors application peut à tout moment appeler la fonction eval() pour exécuter dynamiquement le code généré.

Restrictions relatives à l’accès aux interfaces de programmation AIR (pour des sandbox hors application)

Le code JavaScript dans un sandbox hors application n’a pas accès à l’objet window.runtime et, de ce fait, il ne peut pas exécuter d’interfaces de programmation AIR. Si un contenu, dans un sandbox de sécurité hors application, appelle le code ci-dessous, l’application renvoie une exception TypeError.

try { 
    window.runtime.flash.system.NativeApplication.nativeApplication.exit(); 
}  
catch (e)  
{ 
    alert(e); 
}

Le type d’exception est TypeError (valeur non définie) parce que le contenu du sandbox hors application ne reconnaît pas l’objet window.runtime de sorte qu’il est considéré comme une valeur non définie.

Vous pouvez présenter les fonctionnalités du moteur d’exécution dans un sandbox hors application à l’aide d’un pont de script. Pour plus d’informations, voir Programmation entre contenu d’application et contenu hors application .

Restrictions relatives à l’utilisation des appels XMLHttpRequest

Le contenu HTML du sandbox de sécurité de l’application utilise des méthodes XMLHttpRequest pour charger des données à partir d’emplacements hors du sandbox de l’application au cours du chargement du contenu HTML et de l’exécution de l’événement onLoad .

Par défaut, un contenu HTML dans des sandbox de sécurité hors application n’est pas autorisé à utiliser l’objet XMLHttpRequest de JavaScript pour charger des données à partir des domaines autres que le domaine qui appelle la requête. Une balise image ou iframe peut contenir un attribut allowcrosscomainxhr . La définition de cet attribut sur toute valeur non nulle permet au contenu de l’image ou de l’iframe d’utiliser l’objet XMLHttpRequest de JavaScript pour charger les données à partir de domaines autres que celui du code qui appelle la requête.

<iframe id="UI" 
    src="http://example.com/ui.html" 
    sandboxRoot="http://example.com/" 
    allowcrossDomainxhr="true" 
    documentRoot="app:/"> 
</iframe>

Pour plus d’informations, voir Programmation entre contenus de différents domaines .

Restrictions relatives au chargement d’éléments de CSS, d’image, d’iframe et d’img (pour un contenu dans des sandbox hors application)

Un contenu HTML dans un sandbox de sécurité distant (réseau) ne peut charger que du contenu CSS, image , iframe et img à partir de sandbox distants (à partir d’URL du réseau).

Un contenu HTML dans un sandbox local avec système de fichiers, local avec réseau ou approuvé localement ne peut charger que du contenu CSS, image, iframe et img à partir de sandbox locaux (mais pas à partir de sandbox d’application ou distants).

Restrictions relatives à l’appel de la méthode window.open() de JavaScript

Si une fenêtre créée par un appel à la méthode window.open() de JavaScript affiche un contenu à partir d’un sandbox de sécurité hors application, le titre de la fenêtre commence par celui de la fenêtre principale (de lancement), suivi du caractère deux points (:). Il n’est pas possible d’utiliser du code pour retirer cette partie du titre de l’écran.

Le contenu d’un sandbox de sécurité hors application ne peut réussir un appel à la méthode window.open() de JavaScript que s’il répond à un événement déclenché par la souris ou le clavier de l’utilisateur. Cette condition permet d’éviter qu’un contenu hors application ne crée des fenêtres qui pourraient être utilisées de façon trompeuse, par exemple pour des attaques d’hameçonnage. En outre, le gestionnaire d’événement pour l’événement de la souris ou du clavier ne peut pas paramétrer la méthode window.open() pour qu’elle s’exécute au bout d’un certain temps, par exemple en appelant la fonction setTimeout() .

Le contenu d’un sandbox distant (réseau) ne peut utiliser la méthode window.open() que pour ouvrir le contenu dans un sandbox de réseau distant. Il ne peut pas utiliser cette méthode pour ouvrir du contenu à partir de l’application ou d’un sandbox local.

Un contenu de sandbox local avec système de fichiers, sandbox local avec réseau ou sandbox approuvé localement (voir Sandbox de sécurité ) ne fait appel à la méthode window.open() que pour ouvrir un contenu dans un sandbox local. Il ne peut pas utiliser cette méthode pour ouvrir du contenu à partir de l’application ou d’un sandbox distant.

Erreurs lors de l’appel de code interdit

Si vous appelez du code interdit d’exécution dans un sandbox en raison de ces restrictions liées à la sécurité, le moteur d’exécution distribue une erreur JavaScript : « Violation des règles de sécurité dans le sandbox de sécurité de l’application par le moteur d’exécution d’Adobe AIR sur du code JavaScript ».

Pour plus d’informations, voir la section Contournement des erreurs JavaScript liées à la sécurité .

Protection du sandbox lors du chargement de contenu HTML depuis une chaîne

La méthode loadString() de la classe HTMLLoader vous permet de créer du contenu HTML au moment de l’exécution. Toutefois, les données utilisées comme contenu HTML peuvent être corrompues lorsqu’elles sont chargées à partir d’une source Internet non sécurisée. De ce fait, par défaut, le contenu HTML créé à l’aide de la méthode loadString() n’est pas placé dans le sandbox de l’application et n’a pas accès aux API AIR. Vous pouvez cependant définir la propriété placeLoadStringContentInApplicationSandbox d’un objet HTMLLoader sur true pour placer le contenu HTML créé avec la méthode loadString() dans le sandbox de l’application. Pour plus d’informations, voir la section Chargement de contenu HTML depuis une chaîne .