A Política de Segurança de Conteúdo pode reduzir significativamente o risco e o impacto de ataques de scripting em vários sites em navegadores mais recentes.
O modelo de segurança da Web tem como base uma
política de mesma origem. Por exemplo,
o código de https://mybank.com
precisa ter acesso apenas aos dados de https://mybank.com
, e https://evil.example.com
nunca pode ter acesso permitido.
Em teoria, cada origem é mantida isolada do restante da Web, oferecendo aos desenvolvedores um sandbox seguro para criação. No entanto, na prática, os invasores
encontraram várias maneiras de subverter o sistema.
Ataques de scripting em vários sites (XSS), por exemplo, burlam a política de mesma origem induzindo um site a enviar código malicioso junto com o conteúdo pretendido. Isso é um grande problema, já que os navegadores confiam que todo o código exibido em uma página faz parte da origem de segurança dela. A Folha de referência de XSS (em inglês) é uma seção detalhada antiga, mas representativa, dos métodos que um invasor pode usar para violar essa confiança injetando código malicioso. Se um invasor injeta qualquer código, ele compromete a sessão do usuário e tem acesso a informações particulares.
Nesta página, descrevemos a Política de Segurança de Conteúdo (CSP) como uma estratégia para reduzir o risco e o impacto de ataques XSS em navegadores modernos.
Componentes da CSP
Para implementar uma CSP eficaz, siga estas etapas:
- Use listas de permissões para informar ao cliente o que é permitido ou não.
- Saiba quais diretivas estão disponíveis.
- Conheça as palavras-chave que usam.
- Restringir o uso de código inline e
eval()
. - Denuncie violações da política ao servidor antes de aplicá-las.
Listas de permissões de origem
Os ataques XSS exploram a incapacidade do navegador de distinguir entre um script que faz
parte do seu aplicativo e um script que foi injetado de maneira maliciosa por um
terceiro. Por exemplo, o Botão +1 do Google na parte inferior desta página carrega e executa o código de https://apis.google.com/js/plusone.js
no contexto da origem desta página.
Confiamos nesse código, mas não podemos esperar que o navegador descubra por conta própria
que o código de apis.google.com
é seguro para ser executado, enquanto o código de
apis.evil.example.com
provavelmente não é. O navegador faz o download e executa com prazer qualquer código solicitado pela página, independentemente da fonte.
O cabeçalho HTTP Content-Security-Policy
da CSP permite criar uma lista de permissões de
fontes de conteúdo confiável e instrui o navegador a executar ou renderizar apenas
recursos dessas fontes. Mesmo que um invasor encontre uma brecha para injetar um
script, ele não vai estar na lista de permissões e, portanto, não será
executado.
Confiamos em apis.google.com
para fornecer um código válido e em nós mesmos
para fazer o mesmo. Confira um exemplo de política que permite que os scripts sejam executados somente
quando vierem de uma dessas duas origens:
Content-Security-Policy: script-src 'self' https://apis.google.com
script-src
é uma diretiva que controla um conjunto de privilégios relacionados ao script para uma página. Esse cabeçalho 'self'
como uma fonte válida de script e
https://apis.google.com
como outra. Agora, o navegador pode fazer o download e executar
JavaScript de apis.google.com
por HTTPS, bem como da origem da página
atual, mas não de nenhuma outra origem. Se um invasor injetar código no
site, o navegador gera um erro e não executa o script injetado.
A política se aplica a uma ampla variedade de recursos
A CSP oferece um conjunto de diretivas de política que permitem um controle granular sobre os recursos que uma página pode carregar, incluindo a script-src
do exemplo anterior.
A lista a seguir descreve o restante das diretivas de recursos a partir do nível 2. Uma especificação de nível 3 foi elaborada, mas em grande parte não é implementada nos principais navegadores.
base-uri
- Restringe os URLs que podem aparecer no elemento
<base>
de uma página. child-src
- Lista os URLs para workers e conteúdo do frame incorporado. Por exemplo,
child-src https://youtube.com
permite a incorporação de vídeos do YouTube, mas não de outras origens. connect-src
- Limita as origens às quais você pode se conectar usando XHR, WebSockets e EventSource.
font-src
- Especifica as origens que podem disponibilizar fontes da Web. Por exemplo, você pode permitir
fontes da Web do Google usando
font-src https://themes.googleusercontent.com
. form-action
- Lista endpoints válidos para envio das tags
<form>
. frame-ancestors
- Especifica as origens que podem incorporar a página atual. Essa diretiva se aplica às tags
<frame>
,<iframe>
,<embed>
e<applet>
. Ele não pode ser usado em tags<meta>
ou em recursos HTML. frame-src
- Esta diretiva foi descontinuada no nível 2, mas foi restaurada no nível 3. Se ele
não estiver presente, o navegador vai voltar para
child-src
. img-src
- Define de onde as imagens podem ser carregadas.
media-src
- Restringe as origens que podem enviar vídeo e áudio.
object-src
- Permite o controle sobre Flash e outros plug-ins.
plugin-types
- Limita os tipos de plug-ins que uma página pode invocar.
report-uri
- Especifica um URL para o qual o navegador envia relatórios quando uma política de segurança de conteúdo é
violada. Essa diretiva não pode ser usada em tags
<meta>
. style-src
- Limita as origens em que uma página pode usar folhas de estilo.
upgrade-insecure-requests
- Instrui o user agent a regravar esquemas de URL alterando HTTP para HTTPS. Essa diretiva é destinada a sites com um grande número de URLs antigos que precisam ser reescritos.
worker-src
- Uma diretiva da CSP de nível 3 que restringe os URLs que podem ser carregados como um worker, um worker compartilhado ou um service worker. Desde julho de 2017, essa diretiva tem implementações limitadas.
Por padrão, o navegador carrega o recurso associado de qualquer origem, sem
restrições, a menos que você defina uma política com uma diretiva específica. Para substituir
o padrão, especifique uma diretiva default-src
. Essa diretiva define os padrões de qualquer
diretiva não especificada que termine com -src
. Por exemplo, se você definir
default-src
como https://example.com
e não especificar uma diretiva font-src
,
será possível carregar fontes somente de https://example.com
.
As diretivas a seguir não usam default-src
como substituta. Lembre-se de que
não defini-las é o mesmo que permitir tudo:
base-uri
form-action
frame-ancestors
plugin-types
report-uri
sandbox
Sintaxe básica da CSP
Para usar as diretivas da CSP, liste-as no cabeçalho HTTP com diretivas separadas por dois pontos. Liste todos os recursos necessários de um tipo específico em uma única diretiva da seguinte maneira:
script-src https://host1.com https://host2.com
Confira a seguir um exemplo de várias diretivas, neste caso para um app da Web
que carrega todos os recursos de uma rede de fornecimento de conteúdo em
https://cdn.example.net
e não usa plug-ins nem conteúdo com frames:
Content-Security-Policy: default-src https://cdn.example.net; child-src 'none'; object-src 'none'
Detalhes da implementação
Os navegadores mais recentes oferecem suporte ao cabeçalho Content-Security-Policy
sem prefixo.
Esse é o cabeçalho recomendado. Os cabeçalhos X-WebKit-CSP
e X-Content-Security-Policy
foram descontinuados nos tutoriais on-line.
A CSP é definida página por página. Será necessário enviar o cabeçalho HTTP com todas as respostas que você quiser proteger. Isso permite que você ajuste a política para páginas específicas com base em suas necessidades específicas. Por exemplo, se um conjunto de páginas em seu site tiver um botão +1, e outros não, você poderá permitir que o código do botão seja carregado somente quando necessário.
A lista de origens de cada diretiva é flexível. É possível especificar fontes por esquema (data:
, https:
) ou variando em especificidade desde somente nome do host (example.com
, que corresponde a qualquer origem nesse host: qualquer esquema, qualquer porta) até um URI totalmente qualificado (https://example.com:443
, que corresponde apenas a HTTPS, somente example.com
e somente à porta 443). Caracteres curinga são aceitos, mas apenas como um esquema,
uma porta ou na posição mais à esquerda do nome do host: *://*.example.com:*
corresponderia
a todos os subdomínios de example.com
(mas não o próprio example.com
), usando
qualquer esquema em qualquer porta.
A lista de origens também aceita quatro palavras-chave:
'none'
não corresponde a nada.'self'
corresponde à origem atual, mas não aos subdomínios dela.'unsafe-inline'
permite JavaScript e CSS inline. Para mais informações, consulte Evitar código inline.- O
'unsafe-eval'
permite mecanismos de texto para JavaScript, comoeval
. Para mais informações, consulte Evitareval()
.
Essas palavras-chave exigem aspas simples. Por exemplo, script-src 'self'
(entre aspas) autoriza a execução de JavaScript do host atual. script-src self
(sem aspas) permite o JavaScript de um servidor chamado "self
" (e não do host atual), o que provavelmente não é o que você quis dizer.
Colocar suas páginas no sandbox
Há mais uma diretiva de que vale a pena falar: sandbox
. Ela é um pouco diferente das outras que vimos, porque impõe restrições a ações que a página pode realizar, e não aos recursos que ela pode carregar. Se a
diretiva sandbox
estiver presente, a página vai ser tratada como se tivesse sido carregada
dentro de um <iframe>
com um atributo sandbox
. Isso pode ter uma grande variedade de efeitos na página: forçar a página a ter uma origem exclusiva e impedir o envio de formulários, entre outros. Está um pouco além do escopo desta página, mas você pode encontrar todos os detalhes sobre os atributos de sandbox válidos na seção "Sandboxing" das especificações HTML5.
A metatag
O mecanismo de entrega preferido das CSPs é um cabeçalho HTTP. No entanto, pode ser útil
definir uma política em uma página diretamente na marcação. Para fazer isso, use uma tag <meta>
com
um atributo http-equiv
:
<meta http-equiv="Content-Security-Policy" content="default-src https://cdn.example.net; child-src 'none'; object-src 'none'">
Não é possível usar para frame-ancestors
, report-uri
ou sandbox
.
Evitar código inline
Por mais poderosas que as listas de permissões baseadas na origem usadas nas diretivas da CSP, elas
não conseguem resolver a maior ameaça representada pelos ataques XSS: a injeção de script in-line.
Se um invasor puder injetar uma tag de script que contenha diretamente algum payload
mal-intencionado (como <script>sendMyDataToEvilDotCom()</script>
), o navegador não
poderá diferenciá-la de uma tag de script in-line legítima. A CSP resolve esse
problema banindo totalmente o script inline.
Essa proibição inclui não apenas scripts incorporados diretamente em tags script
, mas também
manipuladores de eventos inline e URLs javascript:
. Você vai precisar mover o conteúdo das
tags script
para um arquivo externo e substituir os URLs javascript:
e <a ...
onclick="[JAVASCRIPT]">
pelas chamadas addEventListener()
adequadas. Por exemplo,
é possível reescrever o seguinte:
<script>
function doAmazingThings() {
alert('YOU ARE AMAZING!');
}
</script>
<button onclick='doAmazingThings();'>Am I amazing?</button>
para algo mais como:
<!-- amazing.html -->
<script src='amazing.js'></script>
<button id='amazing'>Am I amazing?</button>
// amazing.js
function doAmazingThings() {
alert('YOU ARE AMAZING!');
}
document.addEventListener('DOMContentLoaded', function () {
document.getElementById('amazing')
.addEventListener('click', doAmazingThings);
});
O código reescrito não é compatível apenas com a CSP, mas também alinhado com as práticas recomendadas de Web design. O JavaScript inline mistura estrutura e comportamento de maneiras que tornam o código confuso. Também é mais complicado armazenar em cache e compilar. Mover seu código para recursos externos melhora o desempenho das suas páginas.
Mover tags e atributos style
inline para folhas de estilo externas também é
altamente recomendável para proteger seu site contra ataques de exfiltração de dados
baseados em CSS.
Como permitir temporariamente scripts e estilos inline
É possível ativar scripts e estilos in-line adicionando 'unsafe-inline'
como uma
fonte permitida em uma diretiva
script-src
ou style-src
. A CSP de nível 2 também permite adicionar scripts in-line específicos à
lista de permissões usando um valor de uso único criptográfico (número usado uma vez) ou hash da
seguinte maneira.
Para usar um valor de uso único, atribua um atributo de valor de uso único à tag de script. O valor precisa corresponder a um da lista de fontes confiáveis. Exemplo:
<script nonce="EDNnf03nceIOfn39fn3e9h3sdfa">
// Some inline code I can't remove yet, but need to as soon as possible.
</script>
Adicione o valor de uso único à diretiva script-src
seguindo a palavra-chave nonce-
:
Content-Security-Policy: script-src 'nonce-EDNnf03nceIOfn39fn3e9h3sdfa'
Os valores de uso único precisam ser gerados novamente para cada solicitação da página, e eles não podem ser adivinhados.
Os hashes funcionam de maneira semelhante. Em vez de adicionar código à tag de script, crie um hash SHA do próprio script e adicione-o à diretiva script-src
.
Por exemplo, se a página continha o seguinte:
<script>alert('Hello, world.');</script>
Sua política precisa conter o seguinte:
Content-Security-Policy: script-src 'sha256-qznLcsROx4GACP2dm0UCKCzCG-HiZ1guq6ZZDob_Tng='
O prefixo sha*-
especifica o algoritmo que gera o hash. O exemplo
anterior usa sha256-
, mas a CSP também oferece suporte a sha384-
e sha512-
. Ao gerar o hash, omita as tags <script>
. Letras maiúsculas e espaços em branco
são importantes, incluindo espaços à esquerda e à direita.
Soluções para gerar hashes SHA estão disponíveis em várias linguagens. Usando o Chrome 40 ou posterior, é possível abrir o DevTools e atualizar a página. A guia "Console" mostra mensagens de erro com o hash SHA-256 correto para cada um dos scripts inline.
Evite eval()
Mesmo quando um invasor não pode injetar o script diretamente, ele pode enganar
o aplicativo para que ele converta o texto de entrada em JavaScript executável
e o execute em nome dele. eval()
, new Function()
,
setTimeout([string], …)
e setInterval([string], ...)
são todos os vetores
que atacantes podem usar para executar código malicioso por texto injetado. A resposta padrão da CSP a esse risco é bloquear completamente todos esses vetores.
Isso tem os seguintes efeitos na forma como você cria aplicativos:
- Analise o JSON usando o
JSON.parse
integrado, em vez de depender deeval
. Operações JSON seguras estão disponíveis em todos os navegadores desde o IE8. É necessário reescrever todas as chamadas
setTimeout
ousetInterval
feitas usando funções in-line em vez de strings. Por exemplo, se a página tiver o seguinte:setTimeout("document.querySelector('a').style.display = 'none';", 10);
Reescreva o texto como:
setTimeout(function () { document.querySelector('a').style.display = 'none'; }, 10); ```
Evite modelos inline durante a execução. Muitas bibliotecas de modelos usam
new Function()
com frequência para acelerar a geração de modelos no tempo de execução, o que permite a avaliação de texto malicioso. Alguns frameworks oferecem suporte à CSP, voltando a um analisador robusto na ausência deeval
. A diretiva ng-csp do AngularJS é um bom exemplo disso. No entanto, recomendamos usar uma linguagem de modelo que ofereça pré-compilação, como Handlebars. A pré-compilação dos modelos pode tornar a experiência do usuário ainda mais rápida do que a implementação de tempo de execução mais rápida, além de tornar o site mais seguro.
Se eval()
ou outras funções de texto para JavaScript forem essenciais para seu
aplicativo, ative-as adicionando 'unsafe-eval'
como uma fonte permitida
em uma diretiva script-src
. Não é recomendável fazer isso devido ao risco de injeção de
código.
Denunciar violações da política
Para notificar o servidor sobre bugs que possam permitir a injeção de malware, informe ao navegador que os relatórios de violação no formato JSON são POST
para um local especificado em uma diretiva report-uri
:
Content-Security-Policy: default-src 'self'; ...; report-uri /my_amazing_csp_report_parser;
Esses relatórios têm a seguinte aparência:
{
"csp-report": {
"document-uri": "http://example.org/page.html",
"referrer": "http://evil.example.com/",
"blocked-uri": "http://evil.example.com/evil.js",
"violated-directive": "script-src 'self' https://apis.google.com",
"original-policy": "script-src 'self' https://apis.google.com; report-uri http://example.org/my_amazing_csp_report_parser"
}
}
O relatório contém informações úteis para encontrar a causa de uma violação
da política, incluindo a página em que ocorreu (document-uri
), o
referrer
dessa página, o recurso que violou a política da página (blocked-uri
), a
diretiva específica violada (violated-directive
) e a política completa
da página (original-policy
).
Somente relatório
Se você está começando a usar a CSP, recomendamos usar o modo somente relatório para avaliar o estado do seu app antes de alterar a política. Para fazer isso,
em vez de enviar um cabeçalho Content-Security-Policy
, envie um
cabeçalho Content-Security-Policy-Report-Only
:
Content-Security-Policy-Report-Only: default-src 'self'; ...; report-uri /my_amazing_csp_report_parser;
A política especificada no modo somente relatório não bloqueia recursos restritos, mas envia relatórios de violação para o local especificado. É possível até enviar ambos os cabeçalhos para aplicar uma política e monitorar outra. Essa é uma ótima maneira de testar mudanças na CSP enquanto aplica sua política atual: ative os relatórios para uma nova política, monitore os relatórios de violação e corrija todos os bugs e, quando estiver tudo certo com a nova política, comece a aplicá-la.
Uso no mundo real
A primeira etapa para criar uma política para o app é avaliar os recursos que ele carrega. Depois de entender a estrutura do app, crie uma política com base nos requisitos dele. As seções a seguir mostram alguns casos de uso comuns e o processo de decisão para apoiá-los seguindo as diretrizes da CSP.
Widgets de mídias sociais
- O botão "Gostei" do Facebook
tem várias opções de implementação. Recomendamos usar a versão
<iframe>
para mantê-la no sandbox do restante do seu site. Ela precisa de uma diretivachild-src https://facebook.com
para funcionar corretamente. - O botão Tweet de X depende do acesso a um script.
Mova o script fornecido para um arquivo JavaScript externo e use a
diretiva
script-src https://platform.twitter.com; child-src https://platform.twitter.com
. - Outras plataformas têm requisitos semelhantes e podem ser tratadas de forma semelhante.
Para testar esses recursos, recomendamos definir um
default-src
de'none'
e observar seu console para determinar quais recursos precisam ser ativados.
Para usar vários widgets, combine as diretivas da seguinte maneira:
script-src https://apis.google.com https://platform.twitter.com; child-src https://plusone.google.com https://facebook.com https://platform.twitter.com
Lockdown
Em alguns sites, convém garantir que apenas os recursos locais possam ser carregados. O exemplo a seguir desenvolve uma CSP para o site de um banco, começando com uma política padrão que bloqueia tudo (default-src 'none'
).
O site carrega todas as imagens, estilos e scripts de uma CDN em
https://cdn.mybank.net
e se conecta a https://api.mybank.com/
usando XHR para
recuperar dados. Ele usa frames, mas apenas para páginas locais do site (sem origens de terceiros). Não há Flash no site, fontes nem extras. O
cabeçalho CSP mais restritivo que pode enviar é este:
Content-Security-Policy: default-src 'none'; script-src https://cdn.mybank.net; style-src https://cdn.mybank.net; img-src https://cdn.mybank.net; connect-src https://api.mybank.com; child-src 'self'
Somente SSL
Confira a seguir um exemplo de CSP para um administrador de fórum que quer garantir que todos os recursos no fórum sejam carregados apenas usando canais seguros, mas não tem experiência em programação e não tem recursos para reescrever software de fórum de terceiros cheio de scripts e estilos in-line:
Content-Security-Policy: default-src https:; script-src https: 'unsafe-inline'; style-src https: 'unsafe-inline'
Embora https:
seja especificado em default-src
, as diretivas de script e estilo não herdam essa origem automaticamente. Cada diretiva substitui
o padrão para o tipo específico de recurso.
Desenvolvimento padrão da CSP
O nível 2 da Política de Segurança de Conteúdo é um padrão recomendado do W3C. O grupo de trabalho de segurança de aplicativos da Web da W3C está desenvolvendo a próxima iteração da especificação, a Política de Segurança de Conteúdo de nível 3.
Para acompanhar a discussão sobre esses recursos futuros, consulte os arquivos da lista de e-mails public-webappsec@.