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:
- Política de Segurança de Conteúdo (CSP) na MDN.
- Manifesto – Política de Segurança de Conteúdo naReferênciade Extensões> do Chrome.
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:
O valor e as funções relacionadas estão desativados
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 parapopup.js
. Se estiver a iniciar o programa com código como<body onload="main();">
, considere substituí-lo ao ligar-se aoDOMContentLoaded
evento do documento ou aoload
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
, https
e 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.net
https://*.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-src
object-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
- Política de Segurança de Conteúdo (CSP) na MDN.
- Manifesto – Política de Segurança de Conteúdo naReferênciade Extensões> do Chrome.
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.
Este trabalho é licenciado ao abrigo de uma Licença Internacional creative Commons Attribution 4.0.