Conteúdo cross-scripting em caixas de proteção de segurança distintas

Adobe AIR 1.0 e posterior

O modelo de segurança de tempo de execução isola o código de origens distintas. Cruzando scripts de conteúdo em caixas de proteção de segurança distintas, você pode permitir que o conteúdo de uma caixa de proteção de segurança acesse as propriedades e os métodos selecionados em outra caixa de proteção.

Caixas de proteção de segurança do AIR e código JavaScript

O AIR aplica a política de mesma origem, que impede a interação de código de um domínio com o conteúdo de outro domínio. Todos os arquivos são colocados em uma caixa de proteção com base nas respectivas origens. Normalmente, o conteúdo na caixa de proteção do aplicativo não pode violar o princípio de mesma origem e o conteúdo cross-scripting, carregado de fora do diretório de instalação do aplicativo. No entanto, o AIR oferece algumas técnicas que permitem o cruzamento de scripts em conteúdo "não aplicativo".

Uma das técnicas usa frames ou iframes para mapear conteúdo de aplicativo em uma caixa de proteção de segurança distinta. Qualquer página carregada da área com caixa de proteção do aplicativo se comporta como se tivesse sido carregada do domínio remoto. Por exemplo, mapeando o conteúdo do aplicativo para o domínio example.com , esse conteúdo pode fazer o cruzamento cross-scripting das páginas carregadas desse domínio.

Como essa técnica coloca o conteúdo do aplicativo em uma caixa de proteção distinta, o código nesse conteúdo também não estará mais sujeito às restrições na execução de código em strings avaliadas. Você pode usar essa técnica de mapeamento de caixa de proteção para para atenuar essas restrições, mesmo quando não for necessário fazer o cruzamento de scripts de conteúdo remoto. Mapear conteúdo dessa maneira pode ser muito útil ao trabalhar com uma das várias estruturas JavaScript ou com código existente que dependa das strings de avaliação. No entanto, você deve considerar e se proteger contra o risco adicional de que algum conteúdo não confiável possa ser injetado e executado quando o conteúdo for executado fora da caixa de proteção do aplicativo.

Ao mesmo tempo, o conteúdo de aplicativo mapeado para uma outra caixa de proteção perde o acesso às APIs do AIR, portanto, a técnica de mapeamento de caixa de proteção não pode ser usada para expor a funcionalidade do AIR ao código executado fora da caixa de proteção do aplicativo.

Outra técnica de cruzamento de scripts permite criar uma interface chamada ponte de caixa de proteção entre o conteúdo de uma caixa de proteção "não aplicativo" e seu documento pai na caixa de proteção do aplicativo. A ponte permite que o conteúdo filho acesse as propriedades e os métodos definidos pelo pai e o pai acesse as propriedades e os métodos definidos pelo filho, ou ambos.

Por fim, você também pode executar XMLHttpRequests entre domínios da caixa de proteção do aplicativo e, opcionalmente, de outras caixas de proteção.

Para obter mais informações, consulte Elementos HTML frame e iframe , Segurança HTML no Adobe AIR e O objeto XMLHttpRequest .

Carregamento de conteúdo do aplicativo em uma caixa de proteção "não aplicativo"

Para permitir que o conteúdo do aplicativo faça cruzamento de script de conteúdo carregado de fora do diretório de instalação do aplicativo, você pode usar os elementos frame ou iframe para carregar conteúdo do aplicativo na mesma caixa de proteção de segurança do conteúdo externo. Se você não precisa fazer cruzamento de script de conteúdo remoto, mas ainda assim deseja carregar uma página do seu aplicativo fora da respectiva caixa de proteção, pode usar a mesma técnica, especificando http://localhost/ ou algum outro valor inócuo, como o domínio de origem.

O AIR adiciona os novos atributos sandboxRoot e documentRoot ao elemento frame que permite especificar se o arquivo do aplicativo carregado no frame deve ser mapeado para uma caixa de proteção "não aplicativo". Arquivos que estão sendo resolvidos em um caminho abaixo da URL sandboxRoot são carregados, em vez do diretório documentRoot . Para fins de segurança, o conteúdo do aplicativo carregado dessa maneira é tratado como se na verdade tivesse sido carregado da URL sandboxRoot .

A propriedade sandboxRoot especifica a URL que deve ser usada para determinar a caixa de proteção e o domínio em que o conteúdo do quadro deve ser colocado. Os esquemas de URL file: , http: ou https: devem ser usados. Se você especificar uma URL relativa, o conteúdo permanecerá na caixa de proteção do aplicativo.

A propriedade documentRoot especifica o diretório do qual o conteúdo do quadro 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 sandbox do aplicativo a ser executado na caixa de proteção remota e o domínio www.example.com :

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

A página ui.html pode carregar um arquivo javascript da pasta sandbox local, usando a seguinte tag de script:

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

Ele também pode carregar conteúdo de um diretório no servidor remoto usando uma tag de script como a que segue:

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

A URL sandboxRoot irá mascarar todo conteúdo na mesma URL do servidor remoto. No exemplo anterior, você não podia acessar nenhum conteúdo remoto em www.example.com/local/ (ou qualquer um de seus subdiretórios), pois o AIR remapeia a solicitação para o diretório local do aplicativo. As solicitações são remapeadas, sejam elas derivadas de navegação de página, de uma XMLHttpRequest ou de qualquer outro meio de carregamento de conteúdo.

Configuração de interface de ponte de caixa de proteção

Você pode usar uma ponte de caixa de proteção quando o conteúdo da caixa de proteção do aplicativo tiver que acessar propriedades ou métodos definidos pelo conteúdo em uma caixa de proteção "não aplicativo" , ou quando o conteúdo "não aplicativo" tiver que acessar propriedades e métodos definidos pelo conteúdo na caixa de proteção do aplicativo. Crie uma ponte com as propriedades childSandboxBridge e parentSandboxBridge do objeto window de algum documento filho.

Estabelecimento de uma ponte de caixa de proteção filha

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

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

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

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

Estabelecimento de uma ponte de caixa de proteção pai

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

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

Ao usar essa interface, o conteúdo do quadro filho poderá salvar texto em um arquivo chamado save.txt , mas não terá nenhum outro acesso ao sistema de arquivos. O conteúdo filho poderá chamar a função save da seguinte maneira:

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

O conteúdo do aplicativo deverá expor a interface mais estreita possível para as outras caixas de proteção. O conteúdo "não aplicativo" deve ser considerado não confiável inerentemente, já que ele pode estar sujeito à injeção de código acidental ou mal-intencionado. Você deve colocar as proteções apropriadas no local para impedir o uso inadequado da interface exposta através da ponte da caixa de proteção pai.

Acesso à ponte de caixa de proteção pai durante o carregamento de página

Para que o script de um documento filho acesse uma ponte de caixa de proteção pai, a ponte deve ser configurada antes que o script seja executado. Os objetos window, frame e iframe despacham o evento dominitialize quando uma nova página DOM tiver sido criada, mas antes que qualquer script tenha sido analisado ou que elementos DOM tenham sido adicionados. Você pode usar o evento dominitialize para estabelecer a ponte na sequência de construção de página, cedo o bastante para que todos os scripts no documento filho possam acessá-la.

O exemplo a seguir ilustra como criar uma ponte de caixa de proteção pai em resposta ao evento dominitialize despachado do quadro filho:

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

O seguinte documento child.html ilustra como o conteúdo filho pode acessar a ponte de caixa de proteção pai:

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

Para ouvir o evento dominitialize em uma janela filha, em vez de um quadro, você deve adicionar o ouvinte ao novo objeto window filho criado pela função window.open() :

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

Nesse caso, não há como mapear o conteúdo do aplicativo para uma caixa de proteção "não aplicativo". Essa técnica só é útil quando child.html é carregado de fora do diretório do aplicativo. Você pode ainda mapear conteúdo do aplicativo na janela para uma caixa de proteção "não aplicativo", mas primeiramente, é preciso carregar uma página intermediária que use ela mesma quadros para carregar o documento filho e mapeá-lo para a caixa de proteção desejada.

Se você usar a função createRootWindow() da classe HTMLLoader para criar uma janela, a nova janela não será filha do documento do qual createRootWindow() será chamado. Portanto, você não pode criar uma ponte de caixa de proteção da janela que faz a chamada para um conteúdo "não aplicativo" carregado na nova janela. Em vez disso, você deve carregar uma página intermediária na nova janela que use ela mesma quadros para carregar o documento filho. Em seguida, você pode estabelecer a ponte do documento pai da nova janela para o documento filho carregado no quadro.