Compartilhar via


Utilizar a Política de Segurança de Conteúdo (CSP) para controlar que recursos podem ser executados

Para controlar que conteúdo pode ser executado pela extensão, no ficheiro da manifest.json extensão, utilize a chave e o content_security_policy respetivo valor de cadeia de política, de acordo com a seguinte sintaxe:

{
    ...,
    "content_security_policy": "[policy string]"
    ...
}

Por exemplo, segue-se a política de segurança de conteúdo predefinida, conforme descrito abaixo em Restrições de política predefinidas:

{
    ...,
    "content_security_policy": "script-src 'self'; object-src 'self'; worker-src 'self'"
    ...
}

Para mitigar uma grande classe de potenciais problemas de scripting entre sites, o sistema de extensões do Microsoft Edge incorpora a Política de Segurança de Conteúdo (CSP). O CSP introduz algumas políticas rigorosas que tornam as extensões mais seguras por predefinição e permite-lhe criar e impor regras que regem os tipos de conteúdo que podem ser carregados e executados pelas suas extensões e aplicações.

Em geral, o CSP funciona como um mecanismo de bloqueio/lista de permissões para recursos carregados ou executados pela sua extensão. Definir uma política razoável para a sua extensão permite-lhe considerar cuidadosamente os recursos necessários para a sua extensão e pedir ao browser para garantir que esses são os únicos recursos aos quais a extensão tem acesso. As políticas fornecem segurança para além das permissões de anfitrião dos pedidos de extensão; são uma camada adicional de proteção, não uma substituição.

Por outro lado, numa página Web, essa política é definida através de um cabeçalho HTTP ou através de um meta elemento. No entanto, dentro do sistema de extensões do Microsoft Edge, um cabeçalho HTTP ou um meta elemento não é um mecanismo adequado.

Confira:

Restrições de política predefinidas

Os pacotes que não definem uma manifest_version não têm uma política de segurança de conteúdo predefinida.

Os pacotes que utilizam manifest_version têm a seguinte política de segurança de conteúdo predefinida:

script-src 'self'; object-src 'self'; worker-src 'self'

A política adiciona segurança ao limitar extensões e aplicações de três formas:

Código como o seguinte não funciona:

alert(eval("foo.bar.baz"));
window.setTimeout("alert('hi')", 10);
window.setInterval("alert('hi')", 10);
new Function("return foo.bar.baz");

Avaliar cadeias de JavaScript como esta é um vetor de ataque XSS comum. Em vez disso, deve escrever código como:

alert(foo && foo.bar && foo.bar.baz);
window.setTimeout(function() { alert('hi'); }, 10);
window.setInterval(function() { alert('hi'); }, 10);
function() { return foo && foo.bar && foo.bar.baz };

O JavaScript Inline não é executado

O JavaScript Inline não é executado. Esta restrição proíbe tanto os blocos inline <script> como os processadores de eventos inline, como <button onclick="...">.

A primeira restrição elimina uma enorme classe de ataques de scripting entre sites, impossibilitando a execução acidental do script fornecido por terceiros maliciosos. No entanto, exige que escreva o seu código com uma separação limpo entre conteúdo e comportamento. Um exemplo pode tornar isto mais claro. Pode tentar escrever um pop-up de Ação do Browser como um único pop-up.html que contém o seguinte:

<!doctype html>
<html>
    <head>
        <title>My Awesome Pop-up!</title>
        <script>
            function awesome() {
                // do something awesome!
            }

            function totallyAwesome() {
                // do something TOTALLY awesome!
            }

            function clickHandler(element) {
                setTimeout("awesome(); totallyAwesome()", 1000);
            }

            function main() {
                // Initialization work goes here.
            }
        </script>
    </head>
    <body onload="main();">
        <button onclick="clickHandler(this)">
            Click for awesomeness!
        </button>
    </body>
</html>

No entanto, três coisas têm de mudar para que isto funcione da forma esperada:

  • A clickHandler definição tem de ser movida para um ficheiro JavaScript externo (popup.js pode ser um bom destino).

  • As definições do processador de eventos inline têm de ser reescritas em termos de addEventListener e extraídas para popup.js. Se estiver a iniciar o programa com código como <body onload="main();">, considere substituí-lo ao ligar-se ao DOMContentLoaded evento do documento ou ao load evento da janela, consoante os seus requisitos. Utilize o primeiro, uma vez que geralmente é acionado mais rapidamente.

  • A setTimeout chamada tem de ser reescrita para evitar converter a cadeia "awesome(); totallyAwesome()" em JavaScript para execução.

Estas alterações podem ter um aspeto semelhante ao seguinte:

function awesome() {
    // Do something awesome!
}

function totallyAwesome() {
    // do something TOTALLY awesome!
}

function awesomeTask() {
    awesome();
    totallyAwesome();
}

function clickHandler(e) {
    setTimeout(awesomeTask, 1000);
}

function main() {
    // Initialization work goes here.
}

// Add event listeners once the DOM has fully loaded by listening for the
// `DOMContentLoaded` event on the document, and adding your listeners to
// specific elements when it triggers.
document.addEventListener('DOMContentLoaded', function () {
    document.querySelector('button').addEventListener('click', clickHandler);
    main();
});
<!doctype html>
<html>
    <head>
        <title>My Awesome Pop-up!</title>
        <script src="popup.js"></script>
    </head>
    <body>
        <button>Click for awesomeness!</button>
    </body>
</html>

Apenas os recursos de objetos e scripts locais são carregados

Os recursos de script e objeto só podem ser carregados a partir do pacote de extensão e não da Web em geral. Isto garante que a extensão apenas executa o código que aprovou especificamente, impedindo que um atacante de rede ativo redirecione maliciosamente o seu pedido para um recurso.

Em vez de escrever código que dependa do carregamento do jQuery (ou de qualquer outra biblioteca) a partir de uma CDN externa, considere incluir a versão específica do jQuery no pacote de extensão. Ou seja, em vez de:

<!doctype html>
<html>
    <head>
        <title>My Awesome Pop-up!</title>
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
    </head>
    <body>
        <button>Click for awesomeness!</button>
    </body>
</html>

Em alternativa, utilize a seguinte abordagem. Transfira o ficheiro, inclua-o no seu pacote e escreva:

<!doctype html>
<html>
    <head>
        <title>My Awesome Pop-up!</title>
        <script src="jquery.min.js"></script>
    </head>
    <body>
        <button>Click for awesomeness!</button>
    </body>
</html>

Simplificar a política predefinida

Pode permitir a execução dos seguintes tipos de script:

Os detalhes encontram-se abaixo.

Script inline

Os scripts inline podem ser permitidos ao especificar o hash codificado em base64 do código fonte na política. Este hash tem de ser prefixado pelo algoritmo hash utilizado (sha256, sha384 ou sha512). Por exemplo, veja Utilização de Hash W3C > para <elementos de script>.

Script remoto

Se precisar de alguns recursos externos de JavaScript ou objeto, pode descontrair a política de forma limitada ao permitir a lista de origens seguras a partir das quais os scripts devem ser aceites. Verifique se os recursos de runtime carregados com permissões elevadas de uma extensão são exatamente os recursos esperados e não são substituídos por um atacante de rede ativo. Como os ataques man-in-the-middle são triviais e indetectáveis através de HTTP, essas origens não são aceites.

Atualmente, pode permitir origens que tenham os seguintes esquemas: blob, filesystem, httpse extension. A parte anfitriã da origem tem de ser especificada explicitamente para os https esquemas e extension . Carateres universais genéricos, como https:, https://* e https://*.com não são permitidos; são permitidos carateres universais de subdomínio, como https://*.example.com . Os domínios na lista de Sufixos Públicos também são vistos como domínios genéricos de nível superior. Para carregar um recurso a partir destes domínios, o subdomínio tem de ser explicitamente listado. Por exemplo, https://*.cloudfront.net não é válido, mas https://XXXX.cloudfront.nethttps://*.XXXX.cloudfront.net pode ser allowlisted.

Para facilitar o desenvolvimento, os recursos carregados através de HTTP a partir de servidores no seu computador local podem ser allowlisted. Pode permitir scripts e origens de objetos em qualquer porta de http://127.0.0.1 ou http://localhost.

Observação

A restrição relativamente aos recursos carregados através de HTTP aplica-se apenas aos recursos que são executados diretamente. Ainda está livre, por exemplo, para fazer XMLHTTPRequest ligações a qualquer origem de que goste; a política predefinida não restringe connect-src ou qualquer outra diretiva CSP de qualquer forma.

Uma definição de política mais descontraída que permite que os recursos de script sejam carregados através de example.com HTTPS pode ter o seguinte aspeto:

"content_security_policy": "script-src 'self' https://example.com; object-src 'self'"

Observação

Tanto como script-srcobject-src são definidos pela política. O Microsoft Edge não aceita uma política que não limite cada um destes valores a (pelo menos) "self".

JavaScript avaliado

A política e eval() funções relacionadas, como setTimeout(String), setInterval(String)e new Function(String) podem ser flexíveis ao adicionar unsafe-eval à sua política:

"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'"

No entanto, deve evitar políticas flexíveis. Estes tipos de funções são notórios vetores de ataque XSS.

Apertar a política predefinida

Pode reforçar esta política em qualquer medida que a extensão permita, para aumentar a segurança, em detrimento da conveniência. Para especificar que a extensão só pode carregar recursos de qualquer tipo (imagens, etc.) a partir do pacote de extensão associado, por exemplo, uma política de default-src 'self' pode ser apropriada.

Scripts de conteúdo

A política em debate aplica-se às páginas de fundo e às páginas de eventos da extensão. A forma como os scripts de conteúdo se aplicam aos scripts de conteúdo da extensão é mais complicada.

Geralmente, os scripts de conteúdo não estão sujeitos ao CSP da extensão. Uma vez que os scripts de conteúdo não são HTML, a main impacto disto é que podem ser utilizados eval mesmo que o CSP da extensão não especifique unsafe-eval, embora tal não seja recomendado. Além disso, o CSP da página não se aplica a scripts de conteúdo. Mais complicados são as <script> etiquetas que os scripts de conteúdo criam e colocam no DOM da página em que estão a ser executados. Estes são referenciados como scripts injetados do DOM no futuro.

Os scripts injetados do DOM que são executados imediatamente após a injeção na página são executados como seria de esperar. Imagine um script de conteúdo com o seguinte código como um exemplo simples:

document.write("<script>alert(1);</script>");

Este script de conteúdo causa um alert imediatamente após o document.write(). Tenha em atenção que esta ação é executada independentemente da política especificada por página. No entanto, o comportamento torna-se mais complicado dentro desse script injetado do DOM e para qualquer script que não seja imediatamente executado após a injeção.

Imagine que a extensão está em execução numa página que fornece um CSP associado que especifica script-src 'self'. Agora, imagine que o script de conteúdo executa o seguinte código:

document.write("<button onclick='alert(1);'>click me</button>'");

Se um utilizador clicar nesse botão, o onclick script não é executado. Isto acontece porque o script não foi executado imediatamente e o código que não é interpretado até o click evento ocorrer não é considerado parte do script de conteúdo, pelo que o CSP da página (não da extensão) restringe o comportamento. E como esse CSP não especifica unsafe-inline, o processador de eventos inline está bloqueado.

A forma correta de implementar o comportamento pretendido neste caso é adicionar o onclick processador como uma função a partir do script de conteúdo, da seguinte forma:

document.write("<button id='mybutton'>click me</button>'");
var button = document.getElementById('mybutton');
button.onclick = function() {
      alert(1);
};

Outro problema semelhante ocorrerá se o script de conteúdo executar o seguinte:

var script = document.createElement('script');
script.innerHTML = 'alert(1);'
document.getElementById('body').appendChild(script);

Neste caso, o script é executado e o alerta é apresentado. No entanto, considere este caso:

var script = document.createElement('script');
script.innerHTML = 'eval("alert(1);")';
=document.getElementById('body').appendChild(script);

Enquanto o script inicial é executado, a chamada para eval é bloqueada. Ou seja, embora o runtime do script inicial seja permitido, o comportamento dentro do script é regulado pelo CSP da página. Assim, dependendo da forma como escreve scripts injetados do DOM na sua extensão, as alterações ao CSP da página podem afetar o comportamento da sua extensão.

Uma vez que os scripts de conteúdo não são afetados pelo CSP da página, este é um ótimo motivo para colocar o máximo de comportamento possível da sua extensão no script de conteúdo, em vez de scripts injetados do DOM.

Confira também

Observação

Partes desta página são modificações baseadas no trabalho criado e partilhado pela Google e utilizado de acordo com os termos descritos na Licença Internacional Creative Commons Attribution 4.0. A página original encontra-se aqui.

Licença Creative Commons Este trabalho é licenciado ao abrigo de uma Licença Internacional creative Commons Attribution 4.0.