Seguridad HTML en Adobe AIR

Adobe AIR 1.0 y posterior

Este tema describe la arquitectura de seguridad HTML de AIR y cómo utilizar iframes, fotogramas y el puente de entorno limitado para configurar aplicaciones basadas en HTML e integrar con seguridad el contenido HTML en aplicaciones basadas en SWF.

El motor de ejecución impone reglas y proporciona mecanismos para superar posibles vulnerabilidades de seguridad en HTML y JavaScript. Se imponen las mismas reglas independientemente si la aplicación está principalmente escrita en JavaScript o si se carga el contenido HTML y JavaScript en una aplicación basada en SWF. El contenido en el entorno limitado de la aplicación y en el entorno limitado de seguridad que no pertenece a la aplicación tiene diferentes privilegios. Cuando se carga contenido en un iframe o en un fotograma, el motor de ejecución proporciona un mecanismo seguro de puente de entorno limitado que permite que el contenido en el fotograma o iframe se comunique de forma segura en el entorno limitado de seguridad de la aplicación.

El SDK de AIR proporciona tres clases para representar contenido HTML.

La clase HTMLLoader proporciona una estrecha integración entre el código JavaScript y las API de AIR.

La clase StageWebView es una clase de representación HTML y cuenta con una integración muy limitada con la aplicación host de AIR. El contenido cargado mediante la clase StageWebView nunca se sitúa en el entorno limitado de seguridad de la aplicación y no puede acceder a los datos ni llamar a las funciones en la aplicación host de AIR. En las plataformas de escritorio, la clase StageWebView emplea el motor incorporado HTML de AIR, basado en Webkit, que también utiliza la clase HTMLLoader. En las plataformas móviles, la clase StageWebView utiliza el control HTML proporcionado por el sistema operativo. Por lo tanto, en las plataformas móviles la clase StageWebView presenta las mismas vulnerabilidades y factores de seguridad que el navegador web del sistema.

La clase TextField puede mostrar cadenas de texto HTML. JavaScript no se puede ejecutar, pero el texto puede incluir vínculos e imágenes cargadas de forma externa.

Para más información, consulte Cómo evitar errores de JavaScript relacionados con la seguridad .

Información general sobre la configuración de la aplicación basada en HTML

Los fotogramas e iframes proporcionan una estructura conveniente para organizar contenido HTML en AIR. Los fotogramas proporcionan un medio para mantener la persistencia de datos y para trabajar de forma segura con el contenido remoto.

Dado que HTML en AIR conserva la organización normal basada en la página, el entorno HTML se regenera completamente si el fotograma superior del contenido HTML “navega” a una página diferente. Se pueden usar fotogramas e iframes para conservar la persistencia de datos en AIR, al igual que en una aplicación web ejecutándose en un navegador. Defina los objetos de la aplicación principal en el fotograma superior y persistirán siempre que no permita que el fotograma navegue a una nueva página. Use iframes o fotogramas secundarios para cargar y visualizar las partes transitorias de la aplicación. (Hay varias maneras de mantener la persistencia de datos que se pueden usar además o en lugar de los fotogramas. Estas incluyen cookies, objetos compartidos locales, almacenamiento en archivo local, el almacén de archivo cifrado y el almacenamiento local en base de datos.)

Debido a que HTML en AIR conserva su línea difuminada normal entre el código ejecutable y los datos, AIR sitúa el contenido en el marco superior del entorno HTML en el entorno limitado de la aplicación. Tras el evento de página load , AIR restringe todas las operaciones como, por ejemplo, eval() , que puede convertir una cadena de texto en un objeto ejecutable. Esta restricción se impone aun cuando una aplicación no carga el contenido remoto. Para permitir que el contenido HTML ejecute estas operaciones restringidas, debe utilizar fotogramas o iframes para situar el contenido en un entorno limitado ajeno a la aplicación. (Puede ser necesaria la ejecución de contenido en un marco secundario de entorno limitado cuando se utilizan algunos marcos de aplicación de JavaScript que confían en la función eval() .) Para obtener una lista completa de las restricciones en JavaScript en el entorno limitado de la aplicación, consulte Restricciones de código del contenido en entornos limitados diferentes .

Dado que HTML en AIR conserva la habilidad de cargar contenido remoto posiblemente no seguro, AIR impone una política de mismo origen que evita que el contenido en un dominio interactúe con el contenido en otro. Para permitir la interacción entre el contenido de aplicación y el contenido en otro dominio, se puede configurar un puente que actúe como la interfaz entre un fotograma principal y uno secundario.

Configuración de una relación de entorno limitado principal y secundario

AIR añade los atributos sandboxRoot y documentRoot al los elementos frame e iframe HTML. Estos atributos permiten tratar al contenido de aplicación como si proviniera de otro dominio:

Atributo

Descripción

sandboxRoot

La URL que se debe utilizar para determinar el entorno limitado y dominio donde colocar el contenido del fotograma. Se deben utilizar los esquemas de URL file: , http: o https: .

documentRoot

La URL desde donde cargar el contenido del fotograma. Se deben utilizar los esquemas URL file: , app: o app-storage: .

En el siguiente ejemplo se asigna el contenido instalado en el subdirectorio del entorno limitado de la aplicación para que se ejecute en el entorno limitado remoto y en el dominio www.example.com:

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

Configuración de un puente entre fotogramas principales y secundarios en diferentes entornos limitados o dominios

AIR añade las propiedades childSandboxBridge y parentSandboxBridge al objeto window de cualquier fotograma secundario. Estas propiedades permiten definir puentes para que actúen como interfaces entre un fotograma principal y uno secundario. Cada puente va en una dirección:

childSandboxBridge — La propiedad childSandboxBridge permite que el fotograma secundario exponga una interfaz al contenido en el fotograma principal. Para exponer una interfaz, se debe establecer la propiedad childSandbox a una función u objeto en el fotograma secundario. Entonces puede acceder al objeto o función desde el contenido en el fotograma principal. En el siguiente ejemplo se muestra el modo en que un script ejecutándose en un fotograma secundario puede exponer al fotograma principal un objeto que contiene una función y una propiedad:

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

Si este contenido secundario se encuentra en un iframe y se le asignó un ID de "elemento secundario" , se puede acceder a la interfaz desde el contenido principal leyendo la propiedad childSandboxBridge del fotograma:

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

parentSandboxBridge — La propiedad parentSandboxBridge permite que el fotograma principal exponga una interfaz al contenido en el fotograma secundario. Para exponer una interfaz, se debe establecer la propiedad parentSandbox del fotograma secundario a una función u objeto en el fotograma principal. Entonces puede acceder al objeto o función desde el contenido en el fotograma secundario. En el siguiente ejemplo se muestra el modo en que un script ejecutándose en un fotograma principal puede exponer al fotograma secundario un objeto que contiene una función de guardar:

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

Usando esta interfaz, el contenido en el fotograma secundario podría guardar texto en un archivo denominado save.txt. Sin embargo, no tendría ningún otro acceso al sistema de archivos. En general, el contenido de aplicación debe exponer una interfaz lo más limitada posible a otros entornos limitados. El contenido secundario puede llamar a la función save de la siguiente manera:

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

Si el contenido secundario intenta definir una propiedad del objeto parentSandboxBridge , el motor de ejecución emite una excepción SecurityError. Si el contenido principal intenta definir una propiedad del objeto childSandboxBridge , el motor de ejecución emite una excepción SecurityError.

Restricciones de código del contenido en entornos limitados diferentes

Tal y como se describe en la introducción a este tema, Seguridad HTML en Adobe AIR , el motor de ejecución impone reglas y proporciona mecanismos para superar posibles vulnerabilidades de seguridad en HTML y JavaScript. Este tema lista dichas restricciones. Si el código intenta llamar a estas API restringidas, el motor de ejecución emite un error con el mensaje “Adobe AIR runtime security violation for JavaScript code in the application security sandbox” (Infracción de seguridad del motor de ejecución de Adobe AIR para el código JavaScript en el entorno limitado de seguridad de la aplicación).

Para más información, consulte Cómo evitar errores de JavaScript relacionados con la seguridad .

Restricciones en el uso de la función eval() JavaScript y técnicas similares

Para el contenido HTML en el entorno limitado de seguridad de la aplicación, hay limitaciones en el uso de API que pueden transformar dinámicamente cadenas en código ejecutable después de cargar el código (después de que el evento onload del elemento body se haya distribuido y la función del controlador onload haya terminado de ejecutarse). Esta limitación es para evitar que la aplicación accidentalmente inserte (y ejecute) código desde orígenes que no pertenecen a la aplicación (como dominios de red potencialmente inseguros).

Por ejemplo, si la aplicación usa datos de cadena de un origen remoto para escribir en la propiedad innerHTML de un elemento DOM, la cadena puede incluir código ejecutable (JavaScript) que podría realizar operaciones no seguras. Sin embargo, mientras que el contenido se está cargando, no hay riesgo de que se inserten cadenas remotas en el DOM.

Una restricción es el uso de la función eval() JavaScript. Una vez que se carga el código en el entorno limitado de la aplicación y después de procesar el controlador de eventos onload, solo se puede usar la función eval() en maneras limitadas. Las siguientes reglas se aplican al uso de la función eval() después de que se cargue el código del entorno limitado de seguridad de la aplicación:

  • Se permiten expresiones relacionadas con literales. Por ejemplo:

    eval("null"); 
    eval("3 + .14"); 
    eval("'foo'");
  • Se permiten literales de objetos, como en el siguiente ejemplo:

    { prop1: val1, prop2: val2 }
  • Se prohíben los setter/getters literales de objetos, como en el siguiente ejemplo:

    { get prop1() { ... }, set prop1(v) { ... } }
  • Se permiten literales de conjuntos, como en el siguiente ejemplo:

    [ val1, val2, val3 ]
  • Se prohíben las expresiones relacionadas con las lecturas de propiedades, como en el siguiente ejemplo:

    a.b.c
  • La invocación de función está prohibida.

  • Las definiciones de funciones están prohibidas.

  • La configuración de cualquier propiedad está prohibida.

  • Los literales de funciones están prohibidos .

Sin embargo, mientras se carga el código, antes del evento onload y durante la ejecución de la función del controlador de eventos onload , estas restricciones no se aplican al contenido en el entorno limitado de seguridad de la aplicación.

Por ejemplo, después de cargar el código, el código siguiente hace que el motor de ejecución emita una excepción:

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

El código generado dinámicamente, como el que se crea cuando se llama a la función eval() , presenta un riego de seguridad si se permite dentro del entorno limitado de la aplicación. Por ejemplo, una aplicación puede accidentalmente ejecutar una cadena cargada de un dominio de red y dicha cadena puede tener código malintencionado. Por ejemplo, puede ser código para eliminar o alterar archivos en el equipo del usuario. O puede ser código que informa a un dominio de red que no es de confianza sobre el contenido de un archivo local.

A continuación se incluyen formas de generar código dinámico:

  • Llamar a la función eval() .

  • Usar las propiedades innerHTML o funciones DOM para insertar etiquetas de script que cargan un script fuera del directorio de la aplicación.

  • Usar las propiedades innerHTML o funciones DOM para insertar etiquetas de script que tienen código insertado (en lugar de cargar un script a través del atributo src ).

  • Configurar el atributo src para que las etiquetas script carguen un archivo JavaScript que se encuentra fuera del directorio de la aplicación.

  • Usar el esquema javascript de URL (como en href="javascript:alert('Test')" ).

  • Usar la función setInterval() o setTimout() donde el primer parámetro (definiendo la función para que se ejecute de forma asíncrona) es una cadena (para evaluar) en vez de un nombre de función (como en setTimeout('x = 4', 1000) ).

  • Llamar a document.write() o document.writeln() .

El código en el entorno limitado de seguridad de la aplicación solo puede utilizar estos métodos mientras se carga el contenido.

Estas restricciones no impiden el uso de eval() con los literales de objetos JSON. Esto permite que el contenido de aplicación trabaje con la biblioteca JSON JavaScript. Sin embargo, está restringido en el uso de código JSON sobrecargado (con controladores de eventos).

Para otros marcos de Ajax y bibliotecas de código JavaScript, verifique si el código en el marco o biblioteca funciona dentro de estas restricciones en código generado dinámicamente. Si no funcionan, incluya cualquier contenido que usa el marco o la biblioteca en un entorno limitado de seguridad que no pertenece a la aplicación. Para obtener más información, consulte Restricciones para JavaScript dentro de AIR y Uso de scripts entre contenido de la aplicación y contenido que no pertenece a la aplicación . Adobe mantiene una lista de marcos de Ajax que admiten el entorno limitado de seguridad de aplicación, en http://www.adobe.com/es/products/air/develop/ajax/features/ .

A diferencia del contenido en el entorno limitado de seguridad de la aplicación, el contenido JavaScript en un entorno limitado de seguridad que no pertenece a la aplicación puede llamar a la función eval() para que ejecute dinámicamente el código generado en cualquier momento.

Restricciones para acceder a las API de AIR (para entornos limitados ajenos a la aplicación)

El código JavaScript en un entorno limitado que no pertenece a la aplicación no tiene acceso al objeto window.runtime y como tal este código no puede ejecutar las API de AIR. Si el contenido en un entorno limitado de seguridad que no pertenece a la aplicación llama al siguiente código, la aplicación emite una excepción TypeError:

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

El tipo de excepción es TypeError (valor no definido), porque el contenido en el entorno limitado que no pertenece a la aplicación no reconoce el objeto window.runtime , por lo tanto se lo considera un valor no definido.

Se puede exponer la funcionalidad del motor de ejecución al contenido en un entorno limitado que no pertenece a la aplicación usando un puente de script. Para más información, consulte Uso de scripts entre contenido de la aplicación y contenido que no pertenece a la aplicación .

Restricciones para usar llamadas XMLHttpRequest

El contenido HTML en el entorno limitado de seguridad de la aplicación no puede utilizar métodos XMLHttpRequest sincrónicos para cargar datos desde fuera del entorno limitado de la aplicación mientras se está cargando el contenido HTML y durante el evento onLoad .

De forma predeterminada, el contenido HTML en entornos limitados de seguridad que no pertenecen a la aplicación no pueden usar el objeto JavaScript XMLHttpRequest para cargar datos de dominios que no sea el dominio que llama a la petición. Una etiqueta frame o iframe puede incluir el atributo allowcrosscomainxhr . La configuración de este atributo a cualquier valor que no sea null permite que el contenido en el fotograma o iframe use el objeto XMLHttpRequest JavaScript para cargar datos de dominios que no sea el dominio del código que llama a la petición:

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

Para más información, consulte Creación de scripts entre contenido en diferentes dominios .

Restricciones para cargar elementos CSS, frame, iframe e img (para el contenido en entornos limitados que no pertenecen a la aplicación)

El contenido HTML en los entornos limitados de seguridad remotos (red) solo puede cargar contenido CSS, frame , iframe e img de entornos limitados remotos (de URL de red).

El contenido HTML en los entornos limitados local con sistema de archivos, local con acceso a la red o local de confianza solo pueden cargar contenido CSS, frame, iframe e img de entornos limitados locales (no de aplicaciones o entornos limitados remotos).

Restricciones para llamar al método window.open() JavaScript

Si una ventana que se crea a través de una llamada al método window.open() JavaScript muestra contenido de un entorno limitado de seguridad que no pertenece a la aplicación, el título de la ventana comienza con el título de la ventana principal (de inicio), seguido por dos puntos (:). No se puede utilizar el código para trasladar esa porción del título de la ventana fuera de la pantalla.

El contenido en entornos limitados de seguridad que no pertenecen a la aplicación solo pueden llamar correctamente al método window.open() JavaScript en respuesta a un evento activado por el ratón o interacción del teclado. Esto impide que el contenido que no pertenece a la aplicación cree ventanas que se pueden utilizar maliciosamente (por ejemplo, para ataques de suplantación de identidad (phishing). Asimismo, el controlador de eventos para el evento de ratón o teclado no puede definir el método window.open() para ejecutarse después de una demora (por ejemplo llamando a la función setTimeout() ).

El contenido en entornos limitados remotos (red) solo puede utilizar el método window.open() para abrir el contenido en entornos limitados de red remotos. No puede utilizar el método window.open() para abrir contenido de la aplicación o entornos limitados locales.

El contenido en los entornos limitados local con sistema de archivos, local con acceso a la red o local de confianza (consulte Entornos limitados de seguridad ) solo puede usar el método window.open() para abrir contenido en entornos limitados locales. No puede utilizar el método window.open() para abrir contenido de la aplicación o entornos limitados remotos.

Errores al llamar a código restringido

Si se llama al código que no se puede utilizar en un entorno limitado debido a estas restricciones de seguridad, el motor de ejecución distribuye un error de JavaScript: “Adobe AIR runtime security violation for JavaScript code in the application security sandbox” (Infracción de seguridad del motor de ejecución de Adobe AIR para el código JavaScript en el entorno limitado de seguridad de la aplicación).

Para más información, consulte Cómo evitar errores de JavaScript relacionados con la seguridad .

Protección del entorno limitado al cargar contenido HTML de una cadena

El método loadString() de la clase HTMLLoader permite crear contenido HTML en tiempo de ejecución. No obstante, los datos que se utilizan como contenido HTML pueden verse dañados si la información se carga desde un origen de Internet no seguro. Por este motivo, de forma predeterminada, el código HTML creado con el método loadString() no se sitúa en el entorno limitado de la aplicación y no tiene acceso a las API de AIR. Sin embargo, puede establecer la propiedad placeLoadStringContentInApplicationSandbox de un objeto HTMLLoader en true para que sitúe HTML creado utilizando el método loadString() en el entorno limitado de la aplicación. Para obtener más información, consulte Carga del contenido HTML desde una cadena .