O modelo de segurança da Web está enraizado
política de mesma origem. Código
de https://mybank.com
só devem ter acesso aos de https://mybank.com
dados, e o acesso a https://evil.example.com
nunca deverá ser permitido.
Cada origem fica isolada do restante da Web, oferecendo aos desenvolvedores uma plataforma
sandbox para criar e jogar. Na teoria, isso é perfeitamente brilhante. Em
prática, os atacantes encontraram maneiras inteligentes de subverter o sistema.
Scripting em vários locais (XSS) , por exemplo, ignoram a mesma política de origem, enganando um site para que exibir códigos maliciosos junto com o conteúdo pretendido. Esse é um grande problema, já que os navegadores confiam que todo o código que aparece em uma página é legitimamente parte da origem de segurança dessa página. A Folha de referência de XSS é uma seção transversal antiga, mas representativa, dos métodos que um invasor pode usar violar essa confiança injetando código malicioso. Se um invasor conseguir injeta qualquer código, é praticamente o fim: os dados de sessão do usuário são e informações que deveriam ser mantidas em segredo são vazadas para o The Bad Pessoal. É claro que gostaríamos de evitar isso, se possível.
Essa visão geral destaca uma defesa que pode reduzir significativamente os riscos e o impacto de ataques XSS nos navegadores modernos: a Política de Segurança de Conteúdo (CSP).
Texto longo, leia o resumo
- 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.
- Código embutido e
eval()
são considerados prejudiciais. - Denuncie violações de política ao seu servidor antes de aplicá-las.
Listas de permissões de origem
O problema explorado por ataques XSS é a incapacidade do navegador de distinguir
entre o script que é parte de seu aplicativo e o script que foi
injetados maliciosamente por terceiros. Por exemplo, o botão +1 do Google na
parte inferior desta página carrega e executa
https://apis.google.com/js/plusone.js
no contexto da origem desta página. Qa
mas não podemos esperar que o navegador descubra por conta própria
de apis.google.com
é incrível, enquanto o código de apis.evil.example.com
provavelmente não é. O navegador baixa e executa alegremente todos os códigos que uma página
solicitações, independentemente da origem.
Em vez de confiar cegamente em tudo que um servidor oferece, o CSP define
Content-Security-Policy
, que permite criar uma lista de permissões de
fontes de conteúdo confiável e instrui o navegador a apenas executar ou renderizar
recursos dessas fontes. Mesmo se um invasor puder encontrar um buraco pelo qual
injetar um script, ele não corresponderá à lista de permissões e, portanto, não será
executada.
Como confiamos em apis.google.com
para fornecer códigos válidos, e em nós mesmos
para fazer o mesmo, vamos definir uma política que só permita que o script seja executado quando
vem de uma dessas duas fontes:
Content-Security-Policy: script-src 'self' https://apis.google.com
Simples, certo? Como você provavelmente adivinhou, script-src
é uma diretiva que
controla um conjunto de privilégios relacionados ao script de uma página específica. Especificamos
'self'
como uma origem válida do script, e https://apis.google.com
como
outra. Obedientemente, o navegador baixa e executa JavaScript a partir de
apis.google.com
sobre HTTPS, bem como a partir da origem da página atual.
Com essa política definida, o navegador gera um erro em vez de carregamento de script de qualquer outra origem. Quando um invasor inteligente consegue injetar código em seu site, eles vão se deparar com uma mensagem de erro em vez do que o sucesso que eles esperavam.
A política se aplica a uma ampla variedade de recursos
Enquanto os recursos de script representam os riscos de segurança mais óbvios, o CSP oferece
um conjunto de diretivas de política que permitem um controle bastante granular sobre os recursos
que uma página pode carregar. Como você já conhece o script-src
, o conceito
deve ser clara.
Vamos examinar rapidamente o restante das diretivas de recurso. A lista abaixo representa o estado das diretivas a partir do nível 2. Uma especificação de nível 3 foi publicada, mas ainda não foi implementada nas principais navegadores da Web.
base-uri
restringe os URLs que podem aparecer no elemento<base>
de uma página.child-src
lista os URLs dos workers e do conteúdo do frame incorporado. Para exemplo:child-src https://youtube.com
permitiria a incorporação de vídeos de do YouTube, mas não de outras origens.- O
connect-src
limita as origens às quais você pode se conectar (via XHR, WebSockets e EventSource). font-src
especifica as origens que podem disponibilizar fontes da Web. Web do Google as fontes podem ser ativadas porfont-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>
. Essa diretiva não pode ser usada em tags<meta>
e se aplica somente a tags que não sejam HTML do Google Cloud.- O
frame-src
foi descontinuado no nível 2, mas foi restaurado no nível 3. Caso contrário presente, ela ainda volta parachild-src
como antes. img-src
define as origens de onde as imagens podem ser carregadas.- O
media-src
restringe as origens com permissão para entregar vídeo e áudio. object-src
permite o controle do Flash e de outros plug-ins.- O
plugin-types
limita os tipos de plug-ins que uma página pode invocar. report-uri
especifica um URL para onde um navegador enviará relatórios quando uma política de segurança de conteúdo for violada. Esta diretiva não pode ser usada em<meta>
.style-src
é a versão descript-src
das folhas de estilo.- O
upgrade-insecure-requests
instrui os user agents a reescrever esquemas de URL. mudando de HTTP para HTTPS. Essa diretiva é destinada a sites com um grande número de URLs antigos que precisam ser reescritos. worker-src
é uma diretiva de nível 3 da CSP que restringe os URLs que podem ser carregados como um worker, worker compartilhado ou service worker. A partir de julho de 2017, diretiva tem implementações limitadas.
Por padrão, as diretivas são esparsas. Se você não definir uma política específica para
diretriz font-src
, ela se comportará por padrão como
mesmo que você tenha especificado *
como a fonte válida (por exemplo, você pode carregar fontes de
em qualquer lugar, sem restrições).
Para substituir esse comportamento padrão, especifique um default-src
.
diretiva. Essa diretiva define os padrões para a maioria
diretivas que não forem especificadas. Geralmente, isso se aplica a qualquer diretiva que
termina com -src
. Se default-src
for definido como https://example.com
e você falhar
para especificar uma diretiva font-src
, é possível carregar fontes
https://example.com
e nenhum outro lugar. Especificamos apenas script-src
na nossa
dos exemplos anteriores, o que significa que é possível carregar imagens, fontes etc.
qualquer origem.
As diretivas a seguir não usam default-src
como substituto. Lembre-se:
não configurá-los é o mesmo que permitir qualquer coisa.
base-uri
form-action
frame-ancestors
plugin-types
report-uri
sandbox
É possível usar quantas diretivas forem necessárias ao seu
aplicativo específico, simplesmente listando cada um no cabeçalho HTTP, separando
diretivas com ponto e vírgula. Lembre-se de listar todos
recursos obrigatórios de um tipo específico em uma única diretiva. Se você escreveu
algo como script-src https://host1.com; script-src https://host2.com
o
segunda diretiva será ignorada. Algo como o exemplo a seguir
especificar corretamente ambas as origens como válidas:
script-src https://host1.com https://host2.com
Se, por exemplo, você tiver um aplicativo que carrega todos os recursos de uma
rede de fornecimento de conteúdo (por exemplo, https://cdn.example.net
) e saber que você
não necessitar de conteúdo com frames ou plug-ins, sua política poderá parecer algo
como o seguinte:
Content-Security-Policy: default-src https://cdn.example.net; child-src 'none'; object-src 'none'
Detalhes da implementação
Você vai encontrar os cabeçalhos X-WebKit-CSP
e X-Content-Security-Policy
em várias
tutoriais na Web. A partir de agora, você deve ignorar essas regras
e cabeçalhos de cache válidos. Os navegadores modernos (exceto o IE) oferecem suporte à
Cabeçalho Content-Security-Policy
. Esse é o cabeçalho que você deve usar.
Independentemente do cabeçalho usado, a política é definida página por página: você precisa enviar o cabeçalho HTTP junto com cada resposta que deseja garantem a proteção. Isso oferece muita flexibilidade, pois você pode ajustar a política para páginas específicas com base nas necessidades específicas. Talvez um conjunto de páginas em seu site têm um botão +1, enquanto outras não. Você pode permitir que o o código do botão seja carregado somente quando necessário.
A lista de fontes em cada diretiva é flexível. É possível especificar origens
(data:
, https:
) ou variando em especificidade de somente nome do host
(example.com
, que corresponde a qualquer origem nesse host: qualquer esquema, qualquer porta) para
um URI totalmente qualificado (https://example.com:443
, que corresponde apenas a HTTPS,
example.com
e apenas a porta 443). Curingas são aceitos, mas apenas como esquema,
uma porta ou na posição mais à esquerda do nome do host: *://*.example.com:*
corresponder a todos os subdomínios de example.com
(mas não da própria example.com
), usando
qualquer esquema, em qualquer porta.
A lista de fontes também aceita quatro palavras-chave:
- Como é de se esperar,
'none'
não corresponde a nada. 'self'
corresponde à origem atual, mas não aos subdomínios dela.'unsafe-inline'
permite JavaScript e CSS inline. Falaremos sobre isso em mais detalhes daqui a pouco.- O
'unsafe-eval'
permite mecanismos de texto para JavaScript, comoeval
. (Vamos ter aqui também.
Essas palavras-chave exigem aspas simples. Por exemplo, script-src 'self'
(entre aspas)
autoriza a execução de JavaScript a partir do host atual; script-src self
(sem aspas) permite JavaScript de um servidor chamado "self
" (e não do
host atual), o que provavelmente não é o que você quis dizer.
Sandbox
Há mais uma diretiva de que vale a pena falar: sandbox
. É um pouco
diferente das outras que vimos, já que impõe restrições a ações que
pode ocupar a página, e não os recursos que ela carrega. Se o
A diretiva sandbox
está presente, a página é tratada como se tivesse sido carregada
em um <iframe>
com um atributo sandbox
. Isso pode ter uma ampla gama
efeitos na página: forçar a página a ter uma origem exclusiva e impedir que a forma
do projeto, entre outros. Está um pouco além do escopo deste artigo, mas você
você pode encontrar detalhes completos sobre os atributos válidos do sandbox na
"Sandbox" da especificação HTML5.
A metatag
O mecanismo de entrega preferido dos CSPs é um cabeçalho HTTP. Pode ser útil, no entanto,
para 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'"
/>
Esse recurso não pode ser usado para frame-ancestors
, report-uri
ou sandbox
.
Código embutido é considerado nocivo
Deve ficar claro que a CSP é baseada nas origens da lista de permissões, já que essa
forma inequívoca de instruir o navegador a tratar conjuntos específicos de recursos
como aceitável e rejeitar o restante. As listas de permissões baseadas na origem não.
No entanto, resolva a maior ameaça dos ataques XSS: a injeção de script inline.
Se um invasor injetar uma tag script que contém diretamente algum
payload (<script>sendMyDataToEvilDotCom();</script>
),
o navegador não tem um mecanismo para distingui-lo de um navegador
tag de script inline. O CSP resolve esse problema banindo totalmente o script em linha:
é a única maneira de ter certeza.
Essa proibição inclui não apenas scripts incorporados diretamente em tags script
, mas também
manipuladores de eventos inline e URLs javascript:
. Você precisará mover o conteúdo de
script
em um arquivo externo e substitua os URLs javascript:
e <a ... onclick="[JAVASCRIPT]">
pelas chamadas addEventListener()
adequadas. Por exemplo:
você pode reescrever o seguinte:
<script>
function doAmazingThings() {
alert('YOU AM 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>
<div style="clear:both;"></div>
// amazing.js
function doAmazingThings() {
alert('YOU AM AMAZING!');
}
document.addEventListener('DOMContentLoaded', function () {
document.getElementById('amazing').addEventListener('click', doAmazingThings);
});
O código reescrito tem uma série de vantagens além de funcionar bem com CSP; isso já é uma prática recomendada, independente do uso da CSP. Em linha O JavaScript mistura estrutura e comportamento exatamente como não deveria. Recursos externos são mais fáceis para os navegadores armazenarem em cache, mais compreensíveis para desenvolvedores e propício para compilação e minificação. Você escreverá melhor código se você fizer o trabalho de movê-lo para recursos externos.
O estilo in-line é tratado da mesma maneira: os atributos style
e style
as tags devem ser consolidadas em folhas de estilo externas para proteger contra uma
uma variedade de recursos surpreendentemente inteligentes
os métodos de exfiltração de dados que o CSS permite.
Se você precisa ter script e estilo in-line, pode ativá-los
adicionando 'unsafe-inline'
como uma origem permitida em uma script-src
ou style-src
diretiva. Você também pode usar um valor de uso único ou um hash (confira abaixo), o que não é recomendável.
Banir script em linha é a maior vantagem de segurança que a CSP oferece, e
bani-lo também aumenta a proteção do aplicativo. É um pouco de
um esforço antecipado para garantir que tudo funcione corretamente depois de mover todo o código
fora dos padrões, mas é uma troca que vale a pena fazer.
Se for realmente necessário usá-lo,
A CSP de nível 2 oferece compatibilidade com versões anteriores para scripts inline, permitindo que você adicionar scripts inline específicos à lista de permissões usando um valor de uso único criptográfico (número usada apenas uma vez) ou um hash. Embora isso possa ser complicado, é útil rapidamente.
Para usar um valor de uso único, atribua um atributo de valor de uso único à tag de script. Seu valor deve corresponder a um na lista de fontes confiáveis. Exemplo:
<script nonce="EDNnf03nceIOfn39fn3e9h3sdfa">
// Some inline code I can't remove yet, but need to asap.
</script>
Agora, adicione o valor de uso único à diretiva script-src
anexada à palavra-chave nonce-
.
Content-Security-Policy: script-src 'nonce-EDNnf03nceIOfn39fn3e9h3sdfa'
Lembre-se de que os valores de uso único precisam ser gerados novamente para cada solicitação de página e precisam ser não adivinhe.
Os hashes funcionam da mesma forma. Em vez de adicionar código à tag script,
criar um hash SHA do próprio script e adicioná-lo à diretiva script-src
.
Por exemplo, digamos que sua página tenha o seguinte conteúdo:
<script>
alert('Hello, world.');
</script>
Sua política conteria o seguinte:
Content-Security-Policy: script-src 'sha256-qznLcsROx4GACP2dm0UCKCzCG-HiZ1guq6ZZDob_Tng='
Há algumas coisas a serem observadas aqui. O prefixo sha*-
especifica o algoritmo.
que gera o hash. No exemplo acima, usamos sha256-
. O CSP também
oferece suporte a sha384-
e sha512-
. Ao gerar o hash, não inclua o
<script>
. Além disso, letras maiúsculas e espaços são importantes, incluindo letras maiúsculas ou
espaço em branco à direita.
Uma pesquisa no Google sobre como gerar hashes SHA levará você a soluções em qualquer vários idiomas. Usando o Chrome 40 ou posterior, você pode abrir o DevTools e atualize a página. A guia "Console" conterá mensagens de erro com as sha256 para cada um dos scripts inline.
Eval também
Mesmo quando um invasor não consegue injetar um script diretamente, ele pode conseguir enganar
seu aplicativo para converter um texto inerte em JavaScript executável
e executá-la em nome deles. eval()
, novo
Function(), setTimeout([string], ...)
e
setInterval([string], ...)
são todos os vetores pelos quais
pode acabar executando algo inesperadamente malicioso. Padrão do CSP
resposta a esse risco é bloquear completamente todos esses vetores.
Isso causa alguns impactos na maneira como você cria aplicativos:
- Você precisa analisar o JSON pelo
JSON.parse
integrado em vez de depender daeval
. As operações JSON nativas estão disponíveis em desde o IE8, e eles são totalmente seguros. - Reescreva as chamadas
setTimeout
ousetInterval
que você estiver fazendo no momento com funções inline em vez de strings. Exemplo:
setTimeout("document.querySelector('a').style.display = 'none';", 10);
seria melhor escrito como:
setTimeout(function () {
document.querySelector('a').style.display = 'none';
}, 10);
- Evite modelos inline durante a execução: muitas bibliotecas de modelos usam
new Function()
abundantemente para acelerar a geração de modelos no momento da execução. É um boa aplicação de programação dinâmica, mas com o risco de e avaliação de texto malicioso. Alguns frameworks oferecem suporte ao CSP pronto para uso, usando um analisador robusto na ausência deeval
. Diretiva ng-csp do AngularJS é um bom exemplo disso.
No entanto, uma escolha melhor seria uma linguagem de modelo que ofereça
pré-compilação (o Handlebars faz,
por exemplo). A pré-compilação dos modelos pode tornar a experiência do usuário ainda
mais rápida do que a implementação de ambiente de execução mais rápida, além de ser mais segura. Se a avaliação e
de texto para JavaScript são essenciais para o aplicativo,
ative-os adicionando 'unsafe-eval'
como uma origem permitida em um script-src
mas isso não é recomendável. Banindo a capacidade de execução
dificulta a execução de arquivos sem autorização
no seu site.
Relatórios
A capacidade do CSP de bloquear recursos não confiáveis do lado do cliente é uma grande vitória para sua
mas seria muito útil ter algum tipo de notificação
enviadas de volta ao servidor para que você possa identificar e eliminar bugs que permitam
por uma injeção maliciosa. Para isso, é possível instruir o
navegador para POST
relatórios de violação no formato JSON em um local
especificados em uma diretiva report-uri
.
Content-Security-Policy: default-src 'self'; ...; report-uri /my_amazing_csp_report_parser;
Esses relatórios serão semelhantes a estes:
{
"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"
}
}
Ela contém muitas informações que ajudarão você a rastrear
a causa específica da violação, incluindo a página em que ela ocorreu;
ocorreu (document-uri
), o referenciador da página (diferente do método HTTP
cabeçalho, a chave não está incorreta), o recurso que violou o
política da página (blocked-uri
), a diretiva específica que ela violou
(violated-directive
) e a política completa da página (original-policy
).
Somente relatório
Se você está começando a usar o CSP, faz sentido avaliar a experiência
estado do seu aplicativo antes de lançar uma política drástica para seus usuários.
Como degrau para uma implantação completa, você pode pedir ao navegador para monitorar
uma política, denunciando violações, mas não aplicando as restrições. 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órios não bloqueia recursos restritos, mas ele enviará denúncias de violação ao local especificado. É possível até enviar os dois cabeçalhos, aplicando uma política e monitorando outra ao mesmo tempo. Esta é uma ótima de avaliar o efeito das alterações na CSP do seu aplicativo: informar sobre uma nova política, monitorar as denúncias de violação e corrigir os bugs aumentar; Quando você achar que o resultado está bom, comece a aplicar a nova política.
Uso no mundo real
A CSP 1 pode ser usada no Chrome, Safari e Firefox, mas tem limitações compatível com o IE 10. Você pode veja mais detalhes em caniuse.com (link em inglês). A CSP de nível 2 está disponível no Chrome desde versão 40. Sites como o Twitter e o Facebook implantaram o cabeçalho. (vale a pena ler o estudo de caso do Twitter), e o padrão está muito pronto para você começar a implantar nos seus sites.
A primeira etapa para criar uma política para seu aplicativo é avaliar recursos que estão sendo carregados. Quando você achar que já entende como no seu app, configure uma política com base nessas e cumprimento de requisitos regulatórios. Vamos analisar alguns casos de uso comuns e determinar como possa oferecer apoio a elas dentro dos limites de proteção do CSP.
Caso de uso 1: widgets de mídias sociais
Botão +1 do Google inclui um script de
https://apis.google.com
e incorpora uma<iframe>
dahttps://plusone.google.com
. Você precisa de uma política que inclua origens para incorporar o botão. Uma política mínima seriascript-src https://apis.google.com; child-src https://plusone.google.com
. Você também precisa para garantir que o snippet de JavaScript fornecido pelo Google seja extraído um arquivo JavaScript externo. Se você tiver uma política baseada no nível 1 usandoframe-src
O nível 2 exigiu que você mudasse parachild-src
. Isso não é mais necessário no CSP de nível 3.Botão "Curtir" do Facebook tem diversas opções de implementação. Recomendamos manter os
<iframe>
, já que ela é colocada no sandbox com segurança do restante do seu site. Ela requer uma diretivachild-src https://facebook.com
para funcionar corretamente. Observação que, por padrão, o código<iframe>
fornecido pelo Facebook carrega um objeto relativo. URL,//facebook.com
. Altere-o para especificar HTTPS explicitamente:https://facebook.com
: Não há motivos para usar HTTP se não for necessário.Botão "Tweet" do Twitter depende do acesso a um script e a um frame, ambos hospedados
https://platform.twitter.com
O Twitter também fornece um URL relativo default; edite o código para especificar HTTPS ao copiá-lo e colá-lo localmente. Tudo vai estar pronto para a açãoscript-src https://platform.twitter.com; child-src https://platform.twitter.com
, desde que você mova o snippet JavaScript que o Twitter fornece em um arquivo JavaScript externo.Outras plataformas têm requisitos semelhantes e podem ser tratadas de forma semelhante. Sugerimos apenas um
default-src
de'none'
e assistir ao console para determinar quais recursos precisam ser ativados para que os widgets funcionem.
Incluir vários widgets é simples: basta combinar a política diretivas de diretiva, lembrando de mesclar todos os recursos de um único tipo em um único diretiva. Se você quisesse os três widgets de mídia social, a política seria assim:
script-src https://apis.google.com https://platform.twitter.com; child-src https://plusone.google.com https://facebook.com https://platform.twitter.com
Caso de uso 2: bloqueio
Imagine por um momento que você administra o site de um banco e quer ter certeza de que
somente os recursos que você mesmo criou poderão ser carregados. Nesse cenário,
comece com uma política padrão que bloqueie absolutamente tudo (default-src 'none'
) e continue a partir daí.
Digamos que o banco carregue todas as imagens, estilos e scripts de uma CDN em
https://cdn.mybank.net
e se conecta via XHR a https://api.mybank.com/
para
extrair vários bits de dados. Os frames são usados, mas somente para páginas locais do
site (sem origens de terceiros). O site não tem Flash, fontes nem fontes
extras. O cabeçalho CSP mais restritivo que poderíamos 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'
Caso de uso 3: somente SSL
Um administrador de fórum de discussão sobre alianças de casamento quer garantir que todos os recursos sejam carregado somente por canais seguros, mas não escreve muito código. reescrevendo grandes pedaços do software de fórum de terceiros, cheios de o script e o estilo em linha estão além das suas habilidades. A política a seguir seria eficaz:
Content-Security-Policy: default-src https:; script-src https: 'unsafe-inline'; style-src https: 'unsafe-inline'
Mesmo que https:
seja especificado em default-src
, o script e o estilo
elas não herdam essa origem automaticamente. Cada diretiva é totalmente
substitui o padrão desse tipo específico de recurso.
O futuro
O nível 2 da Política de Segurança de Conteúdo é um Candidato à recomendação. Grupo de trabalho de segurança de aplicativos da Web do W3C já tiver começado a trabalhar na próxima iteração da especificação, Nível 3 da Política de Segurança de Conteúdo.
Se você tiver interesse na discussão sobre esses próximos recursos, verifique os arquivos da lista de e-mails public-webappsec@, ou participe também.