Segurança HTML no Adobe AIR

Adobe AIR 1.0 e posterior

Este tópico descreve a arquitetura de segurança HTML do AIR e como usar iframes, quadros e a ponte da caixa de proteção para configurar aplicativos baseados em HTML e integrar conteúdo HTML com segurança em aplicativos baseados em SWF.

O tempo de execução aplica regras e oferece mecanismos para dominar possíveis vulnerabilidades de segurança em HTML e JavaScript. As mesmas regras são aplicadas se o aplicativo for gravado principalmente em JavaScript ou se você carregar conteúdo HTML e JavaScript em um aplicativo baseado em SWF. Conteúdo na caixa de proteção do aplicativo e a caixa de proteção de segurança que não seja de aplicativo têm privilégios distintos. Ao carregar o conteúdo em um iframe ou frame, o tempo de execução fornece um mecanismo de ponte de caixa de proteção seguro, que permite que o conteúdo frame ou iframe se comunique de maneira segura com o conteúdo na caixa de proteção de segurança do aplicativo.

O SDK do AIR oferece três classes para renderização de conteúdo HTML.

A classe HTMLLoader proporciona integração entre o código JavaScript e as APIs do AIR.

A classe StageWebView é uma classe de renderização de HTML e tem integração muito limitada com o aplicativo do AIR host. O conteúdo carregado pela classe StageWebView nunca é colocado na caixa de proteção de segurança do aplicativo e não pode acessar dados nem chamar funções no aplicativo do AIR host. Em plataformas de desktop, a classe StageWebView usa o mecanismo HTML incorporado do AIR, com base no Webkit, que também é usado pela classe HTMLLoader. Em plataformas móveis, a classe StageWebView usa o controle HTML fornecido pelo sistema operacional. Assim, em plataformas móveis, a classe StageWebView tem as mesmas considerações e vulnerabilidades de segurança do navegador da Web do sistema.

A classe TextField pode exibir strings de texto em HTML. Nenhum JavaScript pode ser executado, mas o texto pode incluir links e imagens carregadas externamente.

Para obter mais informações, consulte Como evitar erros JavaScript relacionados à segurança .

Visão geral sobre a configuração de aplicativo baseado em HTML

Os Frames e iframes oferecem uma estrutura conveniente para organizar conteúdo HTML no AIR. Os frames oferecem um meio de manter a persistência de dados e trabalhar de maneira segura com conteúdo remoto.

Como o HTML no AIR retém sua organização normal baseada em página, o ambiente HTML será totalmente atualizado, caso o frame superior do conteúdo HTML "navegue" para uma página diferente. Você pode usar frames e iframes para manter a persistência de dados no AIR, da mesma maneira que em um aplicativo da Web em execução em um navegador. Defina os objetos principais do aplicativo no frame superior e eles persistirão, desde que você não permita que o frame navegue para uma nova página. Use frames ou iframes filhos para carregar e exibir as partes transitórias do aplicativo. (Há diversas maneiras de manter a persistência de dados, que podem ser usadas além de ou em vez de frames. Isso inclui cookies, objetos locais compartilhados, armazenamento local de arquivos, depósito de arquivo criptografado e armazenamento de banco de dados local).

Como o HTML no AIR retém sua linha desfocada normal entre o código executável e os dados, o AIR coloca o conteúdo no quadro superior do ambiente HTML, na caixa de proteção do aplicativo. Depois do evento load da página, o AIR restringe quaisquer operações, como eval() , que possam converter uma sequência de caracteres de texto em um objeto executável. Essa restrição é aplicada mesmo quando o aplicativo não carrega conteúdo remoto. Para permitir que o conteúdo em HTML execute essas operações restritas, você deve usar frames ou iframes para colocar o conteúdo em uma caixa de proteção não aplicativo. (Executar conteúdo em um quadro filho de uma caixa de proteção pode ser necessário ao usar algumas estruturas do aplicativo JavaScript que dependem da função eval() .) Para obter uma lista completa das restrições JavaScript na caixa de proteção do aplicativo, consulte Restrições de código de conteúdo em caixas de proteção distintas .

Como o HTML no AIR mantém a capacidade de carregar conteúdo remoto possivelmente inseguro, o AIR aplica a política de mesma origem que impede que o conteúdo de um domínio interaja com o conteúdo de outro domínio. Para permitir a interação entre o conteúdo do aplicativo e o conteúdo de outro domínio, você pode configurar uma ponte para servir como interface entre um frame pai e filho.

Configuração de relacionamento pai-filho de caixa de proteção

O AIR adiciona os atributos sandboxRoot e documentRoot aos elementos frame e iframe de HTML. Esses atributos permitem tratar o conteúdo do aplicativo como se ele tivesse vindo de outro domínio:

Atributo

Descrição

sandboxRoot

A URL que deve ser usada para determinar a caixa de proteção e o domínio em que o conteúdo do frame deve ser colocado. Os esquemas de URL file: , http: ou https: devem ser usados.

documentRoot

A URL da qual o conteúdo do frame deve ser carregado. Os esquemas de URL file: , app: ou app-storage: devem ser usados.

O exemplo a seguir mapeia o conteúdo instalado no subdiretório da caixa de proteção do aplicativo a ser executado na caixa de proteção remota e o domínio www.exemplo.com:

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

Configuração de ponte entre frames pai e filho em caixas de proteção ou domínios distintos

O AIR adiciona as propriedades childSandboxBridge e parentSandboxBridge ao objeto window de qualquer frame filho. Essas propriedades permitem definir pontes para servir como interfaces entre um quadro pai e filho. Cada ponte segue em uma direção:

childSandboxBridge A propriedade childSandboxBridge permite que o frame filho exponha uma interface para o conteúdo do frame pai. Para expor uma interface, você define a propriedade childSandbox como função ou objeto no frame filho. Em seguida, você pode acessar o objeto ou a função do conteúdo no frame pai. O exemplo a seguir mostra como um script que está sendo executado em um frame filho pode expor um objeto contendo uma função e uma propriedade para o respectivo pai:

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

Se esse conteúdo filho estiver em um iframe com id de "child" atribuída, você poderá acessar a interface do conteúdo pai, lendo a propriedade childSandboxBridge do frame:

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

parentSandboxBridge A propriedade parentSandboxBridge permite que o frame pai exponha uma interface para o conteúdo do frame filho. Para expor uma interface, você define a propriedade parentSandbox do frame filho como função ou objeto no frame pai. Em seguida, você pode acessar o objeto ou a função do conteúdo no frame filho. O exemplo a seguir mostra como um script em execução no frame pai pode expor um objeto contendo uma função save para o filho:

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

Ao usar essa interface, o conteúdo no frame filho poderá salvar texto em um arquivo chamado save.txt. No entanto, ele não terá nenhum outro acesso ao sistema de arquivos. Em geral, o conteúdo do aplicativo deve expor a interface mais estreita possível para as outras caixas de proteção. O conteúdo filho poderá chamar a função save da seguinte maneira:

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

Se o conteúdo filho tentar definir uma propriedade do objeto parentSandboxBridge , o tempo de execução lançará uma exceção SecurityError. Se o conteúdo pai tentar definir uma propriedade do objeto childSandboxBridge , o tempo de execução lançará uma exceção SecurityError.

Restrições de código de conteúdo em caixas de proteção distintas

Como discutido na introdução deste tópico, Segurança HTML no Adobe AIR , o tempo de execução aplica regras e fornece mecanismos para dominar possíveis vulnerabilidades de segurança em HTML e JavaScript. Este tópico lista essas restrições. Se o código tentar chamar essas APIs restritas, o tempo de execução lançará um erro com a mensagem "Violação de segurança de tempo de execução do Adobe AIR para código JavaScript na caixa de proteção de segurança do aplicativo".

Para obter mais informações, consulte Como evitar erros JavaScript relacionados à segurança .

Restrições sobre o uso da função eval() de JavaScript e técnicas semelhantes

Para conteúdo HTML na caixa de proteção de segurança do aplicativo há limitações no uso das APIs que podem transformar dinamicamente as strings em código executável após o carregamento do código (após o evento onload do elemento body ter sido despachado e o término de execução da função do manipulador onload ). Isso é para evitar que o aplicativo injete inadvertidamente (e execute) código de fontes "não aplicativo" (como domínios de rede potencialmente inseguros).

Por exemplo, se o aplicativo usa strings de dados de uma fonte remota para gravar na propriedade innerHTML de um elemento DOM, a string pode incluir o código (JavaScript) executável que pode executar operações inseguras. No entanto, enquanto o conteúdo estiver carregando, não há risco de inserir strings remotas no DOM.

Uma restrição está no uso da função eval() de JavaScript. Após o código na caixa de proteção do aplicativo tiver sido carregado e após o processamento do manipulador de eventos onload, você só poderá usar a função eval() de forma limitada. As seguintes regras se aplicam ao uso da função eval() após o código ter sido carregado da caixa de proteção de segurança do aplicativo:

  • São permitidas expressões que envolvem literais. Por exemplo:

    eval("null"); 
    eval("3 + .14"); 
    eval("'foo'");
  • As literais de objeto são permitidos da seguinte maneira:

    { prop1: val1, prop2: val2 }
  • As opções setter/getters de literal de objeto são proibidas , conforme segue:

    { get prop1() { ... }, set prop1(v) { ... } }
  • As literais de matriz são permitidas da seguinte maneira:

    [ val1, val2, val3 ]
  • Expressões que envolvem leituras de propriedades são proibidas , conforme segue:

    a.b.c
  • A chamada de função é proibida .

  • Definições de função são proibidas.

  • A configuração de qualquer propriedade é proibida .

  • As literais de função são proibidas .

No entanto, enquanto o código estiver sendo carregado, antes do evento onload e durante a execução da função do manipulador de eventos onload , essas restrições não serão aplicadas ao conteúdo na caixa de proteção de segurança do aplicativo.

Por exemplo, após o código ser carregado, o código a seguir resultará no lançamento de uma exceção pelo tempo de execução.

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

O código gerado dinamicamente, como o que é feito durante a chamada da função eval() , representaria um risco à segurança se permitido na caixa de proteção do aplicativo. Por exemplo, um aplicativo pode executar inadvertidamente uma string carregada de um domínio de rede e essa string pode conter código mal-intencionado. Por exemplo, esse pode ser um código de exclusão ou alteração de arquivos no computador do usuário. Ou pode ser um código que informa o conteúdo de um arquivo local para um domínio de rede não confiável.

As formas de gerar código dinâmico são as seguintes:

  • Chamando a função eval() .

  • Uso de propriedades innerHTML ou funções DOM para inserir tags de script que carregam um script de fora do diretório do aplicativo.

  • Uso de propriedades innerHTML ou funções DOM para inserir tags de scripts com código inline (em vez de carregar um script através do atributo src ).

  • Configuração do atributo src para que a tag de script carregue um arquivo JavaScript que está fora do diretório do aplicativo.

  • Uso de esquema de URL javascript (como em href="javascript:alert('Test')" ).

  • Uso da função setInterval() ou setTimout() em que o primeiro parâmetro (que define a função para ser executada de forma assíncrona) é uma string (a ser avaliada) em vez de um nome de função (como em setTimeout('x = 4', 1000) ).

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

O código na caixa de proteção de segurança do aplicativo só pode usar esses métodos enquanto o conteúdo estiver sendo carregado.

Essas restrições não impedem o uso de eval() com literais do objeto JSON. Isso permite que o conteúdo do aplicativo trabalhe com a biblioteca JavaScript JSON. No entanto, você não poderá usar código JSON sobrecarregado (com manipuladores de eventos)

Em outras estruturas Ajax e bibliotecas de código JavaScript, certifique-se de que o código na estrutura ou biblioteca funciona dentro dessas restrições em código gerado dinamicamente. Se não funcionarem, inclua algum conteúdo que use a estrutura ou biblioteca em uma caixa de proteção de segurança "não aplicativo". Consulte detalhes em Restrições a JavaScript dentro do AIR e Script entre conteúdo de aplicativo e "não aplicativo" . O Adobe mantém uma lista das estruturas Ajax conhecidas por oferecer suporte à caixa de proteção de segurança do aplicativo, em http://www.adobe.com/products/air/develop/ajax/features/ .

Ao contrário do conteúdo na caixa de proteção de segurança do aplicativo, o conteúdo JavaScript em uma caixa de proteção de segurança "não aplicativo" pode chamar a função eval() para executar código gerado dinamicamente a qualquer momento.

Restrições de acesso às APIs do AIR (para caixas de proteção que não são de aplicativo)

O código JavaScript em uma caixa de proteção "não aplicativo" não tem acesso ao objeto window.runtime e, portanto, esse código não pode executar APIs do AIR. Se o conteúdo em uma caixa de proteção de segurança "não aplicativo" chamar o código a seguir, o aplicativo lançará uma exceção TypeError:

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

O tipo de exceção é TypeError (valor indefinido), porque o conteúdo na caixa de proteção "não aplicativo" não reconhece o objeto window.runtime , portanto, ele é considerado como valor indefinido.

Você pode expor a funcionalidade de tempo de execução ao conteúdo em uma caixa de proteção "não aplicativo" usando uma ponte de script. Para obter detalhes, consulte Script entre conteúdo de aplicativo e "não aplicativo" .

Restrições no uso de chamadas XMLHttpRequest

O conteúdo HTML na caixa de proteção de segurança do aplicativo não pode usar os métodos XMLHttpRequest síncronos para carregar dados de fora da caixa de proteção do aplicativo enquanto o conteúdo HTML estiver sendo carregado e durante o evento onLoad .

Por padrão, o conteúdo HTML nas caixas de proteção de segurança "não aplicativo" não têm permissão para usar o objeto XMLHttpRequest de JavaScript para carregar dados de outros domínios que não o domínio que está chamando a solicitação. A tag frame ou iframe pode incluir um atributo allowcrosscomainxhr . Configurar esse atributo com qualquer valor diferente de "null" permite que o conteúdo no frame ou iframe use o objeto XMLHttpRequest de Javascript para carregar dados de outros domínios que não sejam o domínio do código que está chamando a solicitação:

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

Para obter mais informações, consulte Script entre conteúdos em domínios distintos .

Restrições no carregamento de elementos CSS, frame, iframe e img (para conteúdo em caixas de proteção que não são de aplicativo)

O conteúdo HTML nas caixas de proteção de segurança remota (rede) pode carregar apenas conteúdo CSS, frame , iframe e img de caixas de proteção remotas (de URLs de rede).

O conteúdo HTML nas caixas de proteção local com sistema de arquivos, local com rede ou local confiável só podem carregar conteúdo CSS, frame, iframe e img de caixas de proteção locais (e não de caixas de proteção de aplicativo ou remotas).

Restrições na chamada do método window.open() de JavaScript

Se a janela criada através de uma chamada para o método window.open() de JavaScript exibir conteúdo de uma caixa de proteção de segurança "não aplicativo", o título da janela iniciará com o título da janela principal (inicializada), seguido pelo caractere dois pontos. Você não pode usar código para remover da tela essa parte do título da janela.

O conteúdo nas caixas de proteção de segurança "não aplicativo" só consegue chamar com êxito o método window.open() de JavaScript em resposta a um evento acionado pelo mouse do usuário ou pela interação do teclado. Isso evita que o conteúdo "não aplicativo" crie janelas que possam ser usadas de maneira enganosa (por exemplo, em ataques de phishing). Além disso, o manipulador de eventos do evento de mouse ou teclado não pode configurar o método window.open() para ser executado após um atraso (por exemplo, chamando a função setTimeout() ).

O conteúdo nas caixas de proteção remotas (rede) só podem usar o método window.open() para abrir o conteúdo nas caixas de proteção de rede remota. Ele não pode usar o método window.open() para abrir o conteúdo das caixas de proteção locais ou do aplicativo.

O conteúdo nas caixas de proteção local com sistema de arquivos, local com rede ou local confiável (consulte Caixas de proteção de segurança ) só pode usar o método window.open() para abrir o conteúdo nas caixas de proteção locais. Ele não pode usar o método window.open() para abrir o conteúdo das caixas de proteção remotas ou do aplicativo.

Erros na chamada de código restrito

Se você chamar um código com uso restrito em uma caixa de proteção, devido a essas restrições de segurança, o tempo de execução despachará um erro de JavaScript: "Violação de segurança de tempo de execução do Adobe AIR para código JavaScript na caixa de proteção de segurança do aplicativo."

Para obter mais informações, consulte Como evitar erros JavaScript relacionados à segurança .

Proteção da caixa de proteção ao carregar conteúdo HTML de uma sequência de caracteres

O método loadString() da classe HTMLLoader permite criar conteúdo HTML no tempo de execução. No entanto, os dados usados como conteúdo HTML podem ser corrompidos se forem carregados de uma fonte de Internet insegura. Por esse motivo, por padrão, o HTML criado com o método loadString() não é colocado na caixa de proteção do aplicativo e não tem acesso às APIs do AIR. Entretanto, você pode definir a propriedade placeLoadStringContentInApplicationSandbox de um objeto HTMLLoader como true para inserir o HTML criado usando o método loadString() na caixa de proteção do aplicativo. Para obter mais informações, consulte Carregamento de conteúdo HTML de uma sequência de caracteres .