O sistema de extensões do Chrome aplica uma Política de Segurança de Conteúdo (CSP) padrão bastante rigorosa.
As restrições da política são simples: o script precisa ser movido off-line para arquivos
JavaScript separados, os manipuladores de eventos inline precisam ser convertidos para usar addEventListener
e eval()
é
desativado. Os apps do Chrome têm uma política ainda mais rígida, e estamos muito satisfeitos com as propriedades
de segurança que essas políticas oferecem.
No entanto, reconhecemos que várias bibliotecas usam construções semelhantes a eval()
e eval
, como
new Function()
, para otimizar o desempenho e facilitar a expressão. As bibliotecas de modelos são
especialmente propensas a esse estilo de implementação. Embora alguns (como o Angular.js) ofereçam suporte a CSP
de forma nativa, muitos frameworks conhecidos ainda não foram atualizados para um mecanismo compatível com
o mundo sem eval
das extensões. A remoção do suporte a essa funcionalidade provou ser mais
problemática do que o esperado para os desenvolvedores.
Este documento apresenta o sandbox como um mecanismo seguro para incluir essas bibliotecas nos seus projetos sem comprometer a segurança. Para encurtar, vamos usar o termo extensões, mas o conceito se aplica igualmente aos aplicativos.
Por que usar sandbox?
eval
é perigoso dentro de uma extensão porque o código que ela executa tem acesso a tudo na
do ambiente de alta permissão da extensão. Há uma série de APIs chrome.*
poderosas disponíveis que podem
afetar gravemente a segurança e a privacidade de um usuário. A extração simples de dados é a menor das nossas preocupações.
A solução oferecida é um sandbox em que eval
pode executar código sem acesso aos dados da extensão ou às APIs de alto valor da extensão. Sem dados, sem APIs, sem problemas.
Fazemos isso listando arquivos HTML específicos dentro do pacote de extensão como sendo colocados no sandbox.
Sempre que uma página em sandbox é carregada, ela é movida para uma origem exclusiva e será negada.
acesso às APIs chrome.*
. Se carregarmos essa página isolada em nossa extensão usando um iframe
, podemos
transmitir mensagens para ela, permitir que ela aja de alguma forma com base nessas mensagens e esperar que ela nos transmita um
resultado. Esse mecanismo simples de mensagens nos dá tudo o que precisamos para incluir com segurança as mensagens geradas com eval
no fluxo de trabalho da nossa extensão.
Criar e usar um sandbox.
Se você quiser mergulhar direto no código, pegue a extensão de exemplo de sandbox e comece. É um exemplo funcional de uma API de mensagens pequena criada com base na biblioteca de modelos Handlebars. Ela vai fornecer tudo o que você precisa para começar. Para quem quiser mais explicações, vamos analisar esse exemplo aqui.
Listar arquivos no manifesto
Cada arquivo que deve ser executado em uma sandbox deve estar listado no manifesto da extensão, adicionando um
sandbox
. Essa é uma etapa fundamental e fácil de esquecer. Verifique se
o arquivo em sandbox está listado no manifesto. Neste exemplo, colocamos o arquivo no sandbox de forma inteligente.
chamado "sandbox.html". A entrada do manifesto é assim:
{
...,
"sandbox": {
"pages": ["sandbox.html"]
},
...
}
Carregar o arquivo no sandbox
Para fazer algo interessante com o arquivo no modo sandbox, precisamos carregá-lo em um contexto em que
ela pode ser resolvida pelo código da extensão. Aqui, sandbox.html foi carregado na
Página de eventos (eventpage.html) da extensão usando um iframe
. eventpage.js contém o código
que envia uma mensagem para o sandbox sempre que a ação do navegador é clicada, encontrando o iframe
na página e executando o método postMessage
no contentWindow
. A mensagem é um objeto
contendo duas propriedades: context
e command
. Vamos falar sobre ambos em breve.
chrome.browserAction.onClicked.addListener(function() {
var iframe = document.getElementById('theFrame');
var message = {
command: 'render',
context: {thing: 'world'}
};
iframe.contentWindow.postMessage(message, '*');
});
postMessage
, consulte a documentação da postMessage
no MDN. Ela é bem completa e vale a pena ler. Especificamente, observe que os dados só podem ser transmitidos de um lado para outro se forem serializáveis. As funções, por exemplo, não são.Fazer algo perigoso
Quando o sandbox.html
é carregado, ele carrega a biblioteca Handlebars e cria e compila um objeto inline
da mesma forma que a Handlebars sugere:
<script src="handlebars-1.0.0.beta.6.js"></script>
<script id="hello-world-template" type="text/x-handlebars-template">
<div class="entry">
<h1>Hello, !</h1>
</div>
</script>
<script>
var templates = [];
var source = document.getElementById('hello-world-template').innerHTML;
templates['hello'] = Handlebars.compile(source);
</script>
Isso não falha. Embora o Handlebars.compile
acabe usando new Function
, tudo funciona
exatamente como esperado, e teremos um modelo compilado em templates['hello']
.
Transmita o resultado de volta
Vamos disponibilizar esse modelo para uso configurando um listener de mensagens que aceita comandos
da página de eventos. Vamos usar o command
transmitido para determinar o que precisa ser feito. Você pode
imaginar fazer mais do que apenas renderizar, talvez criar modelos? Talvez gerenciá-las de alguma forma
o código?), e o context
será transmitido diretamente ao modelo para renderização. O HTML renderizado
será retornado à página do evento para que a extensão possa fazer algo útil com ela mais tarde:
<script>
window.addEventListener('message', function(event) {
var command = event.data.command;
var name = event.data.name || 'hello';
switch(command) {
case 'render':
event.source.postMessage({
name: name,
html: templates[name](event.data.context)
}, event.origin);
break;
// case 'somethingElse':
// ...
}
});
</script>
Na página do evento, vamos receber essa mensagem e fazer algo interessante com os dados html
que recebemos. Neste caso, vamos usar uma Notificação na área de trabalho, mas
é totalmente possível usar esse HTML com segurança como parte da interface de usuário da extensão. Inserindo-a via
O innerHTML
não representa um risco de segurança significativo, já que mesmo um comprometimento total do ambiente em sandbox
por algum ataque inteligente não poderiam injetar script perigoso ou conteúdo de plug-in
o contexto da extensão com alta permissão.
Esse mecanismo simplifica a criação de modelos, mas ele não se limita a modelos. Qualquer um código que não funciona imediatamente sob uma Política de Segurança de Conteúdo rigorosa pode ser colocado no sandbox; no na verdade, pode ser útil colocar no sandbox componentes das suas extensões que seriam executados corretamente restringir cada parte do programa ao menor conjunto de privilégios necessários para sejam executados corretamente. A apresentação Como escrever apps da Web seguros e extensões do Chrome (em inglês) do Google O I/O 2012 dá alguns bons exemplos dessa técnica em ação e vale 56 minutos de sua tempo de resposta.