A Política de Segurança de Conteúdo pode reduzir bastante o risco e o impacto de ataques de XSS em navegadores modernos.
O modelo de segurança da Web é baseado em 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.
Em teoria, cada origem é isolada do restante da Web, oferecendo
aos desenvolvedores um sandbox seguro para criar. Na prática, no entanto, os invasores
encontraram várias maneiras de burlar o sistema.
Os ataques de scripting em vários locais (XSS), por exemplo, fogem da mesma política de origem fazendo um site enviar código malicioso junto com o conteúdo pretendido. Esse é um grande problema, porque os navegadores confiam que todo o código mostrado em uma página é uma parte legítima da origem de segurança da página. O guia de consulta rápida de XSS é um detalhamento antigo, mas representativo, dos métodos que podem ser usados por um invasor para violar essa confiança por meio da injeção de código malicioso. Se um invasor injetar qualquer código, ele comprometerá a sessão do usuário e terá acesso a informações particulares.
Esta página descreve a Política de Segurança de Conteúdo (CSP) como uma estratégia para reduzir o risco e o impacto de ataques de XSS em navegadores modernos.
Componentes do CSP
Para implementar um CSP eficaz, siga estas etapas:
- Use listas de permissões para informar o cliente do que é permitido e do que não é.
- Conheça as diretivas disponíveis.
- Conheça as palavras-chave que usam.
- Restringe o uso de código inline e
eval()
. - Relate violações da política ao servidor antes de tomar alguma providência sobre elas.
Listas de permissões de origem
Os ataques XSS exploram a incapacidade do navegador de distinguir entre o script
que faz parte do aplicativo e o que foi injetado de forma maliciosa por um terceiro. Por exemplo, o botão +1 do Google na parte de baixo desta página carrega e
executa o código de https://apis.google.com/js/plusone.js
no contexto da
origem da 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 execução, enquanto o código de
apis.evil.example.com
provavelmente não é. O navegador baixa e
executa todo código que uma página solicita, independentemente da origem.
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 consiga encontrar uma brecha para injetar um
script, ele não vai corresponder à lista de permissões e, portanto, não será
executado.
Confiamos em apis.google.com
para fornecer código válido e confiamos em nós
mesmos para fazer o mesmo. Confira um exemplo de política que permite a execução de scripts apenas
quando eles vêm de uma dessas duas fontes:
Content-Security-Policy: script-src 'self' https://apis.google.com
script-src
é uma diretiva que controla um conjunto de privilégios relacionados a script para
uma página. Esse cabeçalho 'self'
como uma fonte válida de script e
https://apis.google.com
como outra. O navegador agora 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
seu site, o navegador vai gerar um erro e não vai executar o script injetado.
A política é aplicável a diversos recursos
O CSP fornece um conjunto de diretivas de política que permitem o controle granular dos
recursos que uma página pode carregar, incluindo 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 redigida, mas ela não foi implementada em grande parte nos principais navegadores.
base-uri
- Restrição dos URLs que podem aparecer no elemento
<base>
de uma página. child-src
- Lista os URLs para workers e conteúdos de frame incorporados. 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 a que você pode se conectar usando XHR, WebSockets e EventSource.
font-src
- Especifica as origens que podem oferecer fontes da web. Por exemplo, é possível permitir
as fontes da Web do Google usando
font-src https://themes.googleusercontent.com
. form-action
- Lista endpoints válidos para envio de 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 para recursos HTML. frame-src
- Esta diretiva foi descontinuada no nível 2, mas restaurada no nível 3. Se ele não
estiver presente, o navegador vai voltar para
child-src
. img-src
- Define as origens de onde as imagens podem ser carregadas.
media-src
- Restrição das origens que podem fornecer vídeo e áudio.
object-src
- Permite controlar o 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 de onde uma página pode usar folhas de estilo.
upgrade-insecure-requests
- Instrui os agentes do usuário a regravar esquemas de URL, mudando HTTP para HTTPS. Essa diretiva é para sites com um grande número de URLs antigos que precisam ser reescritos.
worker-src
- Uma diretiva do nível 3 do CSP que restringe os URLs que podem ser carregados como worker, worker compartilhado ou 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 para 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
, só será possível carregar fontes de https://example.com
.
As diretivas a seguir não usam default-src
como um fallback. 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 de 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, conforme abaixo:
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 conteúdo em quadros nem plug-ins:
Content-Security-Policy: default-src https://cdn.example.net; child-src 'none'; object-src 'none'
Detalhes da implementação
Os navegadores modernos oferecem suporte ao cabeçalho Content-Security-Policy
sem prefixo.
Este é o cabeçalho recomendado. Os cabeçalhos X-WebKit-CSP
e
X-Content-Security-Policy
que você pode encontrar em tutoriais
on-line foram descontinuados.
O CSP é definido página por página. Você precisa enviar o cabeçalho HTTP com todas as respostas que quer proteger. Isso permite que você ajuste a política para páginas específicas com base nas necessidades delas. Por exemplo, se um conjunto de páginas no seu site tiver um botão +1, enquanto outras não, você poderá permitir que o código do botão seja carregado somente quando necessário.
A lista de origem de cada diretiva é flexível. Você pode especificar fontes por
esquema (data:
, https:
) ou de acordo com a especificidade, desde apenas por nome de host
(example.com
, que corresponde a qualquer origem nesse host: qualquer esquema, qualquer porta) a
um URI totalmente qualificado (https://example.com:443
, que corresponde apenas a HTTPS, apenas
example.com
e apenas a porta 443). Caracteres curinga são aceitos, mas somente como um esquema,
uma porta ou à extrema esquerda do nome do host: *://*.example.com:*
corresponderia
a todos os subdomínios de example.com
(mas não ao próprio example.com
), usando
qualquer esquema em qualquer porta.
A lista de fontes também aceita quatro palavras-chave:
'none'
não corresponde a nada.'self'
corresponde à origem atual, mas não aos subdomínios.'unsafe-inline'
permite JavaScript e CSS inline. Para mais informações, consulte Evitar código inline.'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'
(com aspas)
autoriza a execução de JavaScript no host atual. script-src self
(sem aspas) permite executar JavaScript de um servidor chamado "self
" (e não do
host atual), o que provavelmente não é o que você quer.
Testar suas páginas no sandbox
Há mais uma diretiva de que vale a pena falar: sandbox
. Ela é um pouco
diferente das outras que vimos, já que coloca restrições em ações que
a página pode executar, em vez de em recursos que a página pode carregar. Se a
diretiva sandbox
estiver presente, a página será tratada como se tivesse sido carregada
dentro de um <iframe>
com um atributo sandbox
. Isso pode gerar um monte de
efeitos na página: forçar a página em uma origem única, impedir o envio
de formulários e 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" da especificação HTML5.
A metatag
O mecanismo de fornecimento de CSPs preferido é um cabeçalho HTTP. No entanto, pode ser útil
definir uma política em uma página diretamente na marcação. Faça isso usando 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 esse recurso para frame-ancestors
, report-uri
ou sandbox
.
Evite o código inline
Por mais poderosas que sejam as listas de permissões baseadas na origem usadas nas diretivas do CSP, elas
não podem resolver a maior ameaça apresentada pelos ataques XSS: a injeção de script inline.
Se um invasor conseguir injetar uma tag de script que contenha diretamente um payload
malicioso (como <script>sendMyDataToEvilDotCom()</script>
), o navegador não terá
como diferenciá-la de uma tag de script inline legítima. A CSP resolve esse
problema banindo totalmente o script inline.
Esse banimento inclui não apenas scripts incorporados diretamente nas tags script
, mas também
gerenciadores 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]">
por chamadas addEventListener()
apropriadas. Por exemplo,
você pode reescrever o seguinte:
<script>
function doAmazingThings() {
alert('YOU ARE AMAZING!');
}
</script>
<button onclick='doAmazingThings();'>Am I amazing?</button>
para algo 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 regravado não é apenas compatível com o CSP, mas também está alinhado com as práticas recomendadas de design da Web. O JavaScript inline mistura estrutura e comportamento de maneiras que tornam o código confuso. Também é mais complicado fazer o cache e a compilação. Mover o 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 é
recomendado 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 inline 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 inline específicos à
lista de permissões usando um nonce criptográfico (número usado uma vez) ou um hash da seguinte
maneira.
Para usar um valor de uso único, atribua um atributo de uso único à tag de script. O valor precisa ser igual 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 nonces precisam ser regenerados para cada solicitação de página e não podem ser adivinháveis.
Os hashes funcionam de maneira semelhante. Em vez de adicionar código à tag do script, crie
um hash SHA do próprio script e adicione-o à diretiva script-src
.
Por exemplo, se a página contiver 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 o CSP também oferece suporte a sha384-
e sha512-
. Ao
gerar o hash, omita as tags <script>
. Letras maiúsculas e minúsculas e espaços
fazem diferença, incluindo espaços no início e no fim.
As soluções para gerar hashes SHA estão disponíveis em vários idiomas. Usando o Chrome 40 ou posterior, você pode abrir o DevTools e recarregar 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 que um invasor não consiga injetar o script diretamente, ele pode enganar
seu aplicativo para converter o texto de entrada em JavaScript executável
e executá-lo em nome dele. eval()
, new Function()
,
setTimeout([string], …)
e setInterval([string], ...)
são vetores
que os invasores podem usar para executar códigos maliciosos por meio de texto injetado. A resposta padrão
da CSP a esse risco é o bloqueio total desses vetores.
Isso tem os seguintes efeitos na forma como você desenvolve aplicativos:
- Você precisa analisar JSON usando o
JSON.parse
integrado em vez de depender deeval
. As operações JSON seguras estão disponíveis em todos os navegadores desde o IE8. Reescreva todas as chamadas de
setTimeout
ousetInterval
que você faz usando funções inline em vez de strings. Por exemplo, se a página contiver o seguinte:setTimeout("document.querySelector('a').style.display = 'none';", 10);
Reescreva como:
setTimeout(function () { document.querySelector('a').style.display = 'none'; }, 10); ```
Evite a geração de modelos inline em tempo de execução. Muitas bibliotecas de modelos usam
new Function()
com frequência para acelerar a geração de modelos em tempo de execução, o que permite a avaliação de texto malicioso. Alguns frameworks oferecem suporte a CSP de forma inovadora, usando fallback para um analisador robusto na ausência deeval
. A diretiva ng-csp do AngularJS é um bom exemplo disso. No entanto, recomendamos usar uma linguagem de modelos que ofereça pré-compilação, como Handlebars. Pré-compilar modelos pode deixar a experiência do usuário mais rápida do que a implementação em 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 o
aplicativo, você poderá ativá-las adicionando 'unsafe-eval'
como uma fonte permitida
em uma diretiva script-src
. Não recomendamos isso devido ao risco de injeção
de código.
Denunciar violações da política
Para notificar o servidor sobre bugs que podem permitir a injeção maliciosa, é possível
instruir o navegador a POST
relatórios de violação formatados em JSON 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 são assim:
{
"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
de política, incluindo a página em que ela ocorreu (document-uri
), o
referrer
da página, o recurso que violou a política da página (blocked-uri
), a
diretiva específica que foi violada (violated-directive
) e a política completa
da página (original-policy
).
Somente relatório
Se você está começando a usar o CSP, recomendamos usar o modo somente relatório para
avaliar o estado do app antes de mudar 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 ao local que você especificar. Você pode até enviar ambos os cabeçalhos para aplicar uma política enquanto monitora outra. Essa é uma ótima maneira de testar mudanças na CSP enquanto aplica a política atual: ative os relatórios para uma nova política, monitore os relatórios de violação e corrija os bugs. Quando você estiver satisfeito 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 abordam alguns casos de uso comuns e o processo de decisão para oferecê-los de acordo com as diretrizes do CSP.
Widgets de mídias sociais
- O botão de curtida do Facebook
tem várias opções de implementação. Recomendamos usar a versão
<iframe>
para manter o sandbox do resto do site. Ele precisa de uma diretivachild-src https://facebook.com
para funcionar corretamente. - O botão de Tuíte do 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 similares e podem ser endereçadas de forma parecida.
Para testar esses recursos, recomendamos definir um
default-src
de'none'
e observar o console para determinar quais recursos você precisa ativar.
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
Bloqueio total
Em alguns sites, é importante garantir que apenas recursos locais possam ser
carregados. O exemplo a seguir desenvolve um CSP para um site bancário, começando com
uma política padrão que bloqueia tudo (default-src 'none'
).
O site carrega todas as imagens, estilos e scripts de um CDN em
https://cdn.mybank.net
e se conecta a https://api.mybank.com/
usando XHR para
extrair dados. Ele usa frames, mas apenas para páginas locais do site (sem
origens de terceiros). Não há Flash, fontes nem extras no site. O
cabeçalho CSP mais restritivo que ele 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 abaixo 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 os recursos para reescrever o software de fórum de terceiros cheio de scripts e estilos inline:
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 fonte automaticamente. Cada diretiva substitui
o padrão para esse tipo específico de recurso.
Desenvolvimento de CSP padrão
A Política de segurança de conteúdo de nível 2 é um padrão recomendado do W3C. O Web Application Security Working Group do 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@.