Um guia abrangente para melhorar a segurança do frontend usando Content Security Policy (CSP) e Cross-Origin Resource Sharing (CORS), protegendo seus aplicativos web contra ameaças modernas.
Reforço da Segurança no Frontend: Content Security Policy e CORS
Na paisagem digital interconectada de hoje, a segurança do frontend é fundamental. Os aplicativos web são cada vez mais alvos de ataques sofisticados, tornando as medidas de segurança robustas essenciais. Dois componentes críticos de uma arquitetura de frontend segura são Content Security Policy (CSP) e Cross-Origin Resource Sharing (CORS). Este guia abrangente oferece uma visão aprofundada dessas tecnologias, oferecendo exemplos práticos e insights acionáveis para ajudá-lo a fortalecer seus aplicativos web contra ameaças modernas.
O que é Content Security Policy (CSP)?
Content Security Policy (CSP) é uma camada adicional de segurança que ajuda a detectar e mitigar certos tipos de ataques, incluindo Cross-Site Scripting (XSS) e ataques de injeção de dados. O CSP é implementado pelo servidor web enviando um cabeçalho de resposta HTTP Content-Security-Policy para o navegador. Este cabeçalho define uma lista de permissões de fontes das quais o navegador tem permissão para carregar recursos. Ao restringir as fontes de conteúdo que um navegador pode carregar, o CSP torna significativamente mais difícil para os invasores injetar código malicioso em seu site.
Como o CSP Funciona
O CSP funciona instruindo o navegador a carregar apenas recursos (por exemplo, scripts, folhas de estilo, imagens, fontes) de fontes aprovadas. Essas fontes são especificadas no cabeçalho CSP usando diretivas. Se um navegador tentar carregar um recurso de uma fonte que não é explicitamente permitida, ele bloqueará a solicitação e relatará uma violação.
Diretivas CSP: Uma Visão Geral Abrangente
As diretivas CSP controlam os tipos de recursos que podem ser carregados de fontes específicas. Aqui está uma análise de algumas das diretivas mais importantes:
- default-src: Especifica a fonte padrão para todos os tipos de conteúdo. Esta é uma diretiva de fallback que se aplica quando outras diretivas mais específicas não estão presentes.
- script-src: Especifica as fontes de onde os scripts podem ser carregados. Isso é crucial para prevenir ataques XSS.
- style-src: Especifica as fontes de onde as folhas de estilo podem ser carregadas.
- img-src: Especifica as fontes de onde as imagens podem ser carregadas.
- font-src: Especifica as fontes de onde as fontes podem ser carregadas.
- media-src: Especifica as fontes de onde áudio e vídeo podem ser carregados.
- object-src: Especifica as fontes de onde os plugins (por exemplo, Flash) podem ser carregados. Isso geralmente é definido como 'none' para desativar os plugins completamente devido aos seus riscos de segurança inerentes.
- frame-src: Especifica as fontes de onde os frames (por exemplo, <iframe>) podem ser carregados.
- connect-src: Especifica os URLs aos quais o agente do usuário pode se conectar usando interfaces de script como XMLHttpRequest, WebSocket e EventSource.
- base-uri: Especifica os URLs que podem ser usados no elemento <base> de um documento.
- form-action: Especifica os URLs para os quais os envios de formulários podem ser enviados.
- upgrade-insecure-requests: Instrui o agente do usuário a atualizar automaticamente as solicitações inseguras (HTTP) para solicitações seguras (HTTPS).
- report-uri: Especifica um URL onde o navegador deve enviar relatórios sobre violações de CSP. Esta diretiva foi descontinuada em favor de `report-to`.
- report-to: Especifica um nome de grupo de relatórios definido no cabeçalho `Report-To`, onde o navegador deve enviar relatórios sobre violações de CSP.
Palavras-chave da Lista de Origens do CSP
Dentro das diretivas CSP, você pode usar palavras-chave da lista de origens para definir origens permitidas. Aqui estão algumas palavras-chave comuns:
- 'self': Permite recursos da mesma origem (esquema e host) que o documento.
- 'none': Não permite recursos de todas as origens.
- 'unsafe-inline': Permite o uso de scripts e estilos inline (por exemplo, tags <script> e atributos de estilo). Use com extrema cautela, pois enfraquece significativamente a proteção CSP contra XSS.
- 'unsafe-eval': Permite o uso de funções de avaliação de código dinâmico como
eval()eFunction(). Use com extrema cautela, pois introduz riscos de segurança significativos. - 'unsafe-hashes': Permite manipuladores de eventos inline específicos ou tags <style> que correspondem a um hash especificado. Requer suporte do navegador. Use com cautela.
- 'strict-dynamic': Especifica que a confiança explicitamente dada a um script presente na marcação, acompanhando-o com um nonce ou hash, deve ser propagada para todos os scripts carregados por esse script raiz.
- data: Permite URIs de dados (por exemplo, imagens inline codificadas como base64). Use com cautela.
- https:: Permite que os recursos sejam carregados via HTTPS de qualquer domínio.
- [hostname]: Permite recursos de um domínio específico (por exemplo, example.com). Você também pode especificar um número de porta (por exemplo, example.com:8080).
- [scheme]://[hostname]:[port]: Um URI totalmente qualificado, permitindo recursos do esquema, host e porta especificados.
Exemplos Práticos de CSP
Vamos dar uma olhada em alguns exemplos práticos de cabeçalhos CSP:
Exemplo 1: CSP Básico com 'self'
Esta política permite recursos apenas da mesma origem:
Content-Security-Policy: default-src 'self'
Exemplo 2: Permitindo Scripts de um Domínio Específico
Esta política permite scripts de seu próprio domínio e de uma CDN confiável:
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com
Exemplo 3: Desativando Scripts e Estilos Inline
Esta política não permite scripts e estilos inline, o que é uma forte defesa contra XSS:
Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self'
Importante: Desativar scripts inline requer refatorar seu HTML para mover scripts inline para arquivos externos.
Exemplo 4: Usando Nonces para Scripts Inline
Se você deve usar scripts inline, use nonces (tokens criptograficamente aleatórios e de uso único) para permitir blocos de script inline específicos. Isso é mais seguro do que 'unsafe-inline'. O servidor deve gerar um nonce exclusivo para cada solicitação e incluí-lo no cabeçalho CSP e na tag <script>.
Content-Security-Policy: default-src 'self'; script-src 'nonce-r4nd0mN0nc3'; style-src 'self'
<script nonce="r4nd0mN0nc3"> console.log('Inline script'); </script>
Nota: Lembre-se de gerar um novo nonce para cada solicitação. Não reutilize nonces!
Exemplo 5: Usando Hashes para Estilos Inline
Semelhante aos nonces, os hashes podem ser usados para permitir blocos <style> inline específicos. Isso é feito gerando um hash SHA256, SHA384 ou SHA512 do conteúdo do estilo.
Content-Security-Policy: default-src 'self'; style-src 'sha256-HASHEDSTYLES'
<style sha256="HASHEDSTYLES"> body { background-color: #f0f0f0; } </style>
Nota: Os hashes são menos flexíveis do que os nonces, pois qualquer alteração no conteúdo do estilo invalidará o hash.
Exemplo 6: Relatando Violações de CSP
Para monitorar violações de CSP, use a diretiva report-uri ou report-to:
Content-Security-Policy: default-src 'self'; report-to csp-endpoint;
Você também precisará configurar o cabeçalho Report-To. O cabeçalho Report-To define um ou mais grupos de relatórios, que especificam onde e como os relatórios devem ser enviados.
Report-To: {"group":"csp-endpoint","max_age":10886400,"endpoints":[{"url":"https://example.com/csp-report"}]}
Testando e Implantando CSP
Implementar o CSP requer planejamento e testes cuidadosos. Comece com uma política restritiva e afrouxe-a gradualmente conforme necessário. Use o cabeçalho Content-Security-Policy-Report-Only para testar sua política sem bloquear recursos. Este cabeçalho relata violações sem aplicar a política, permitindo que você identifique e corrija problemas antes de implantar a política em produção.
Content-Security-Policy-Report-Only: default-src 'self'; report-to csp-endpoint;
Analise os relatórios gerados pelo navegador para identificar quaisquer violações e ajustar sua política de acordo. Depois de ter certeza de que sua política está funcionando corretamente, implante-a usando o cabeçalho Content-Security-Policy.
Melhores Práticas para CSP
- Comece com um default-src: Sempre defina um
default-srcpara estabelecer uma política de linha de base. - Seja específico: Use diretivas específicas e palavras-chave da lista de origens para limitar o escopo de sua política.
- Evite 'unsafe-inline' e 'unsafe-eval': Essas palavras-chave enfraquecem significativamente o CSP e devem ser evitadas sempre que possível.
- Use nonces ou hashes para scripts e estilos inline: Se você deve usar scripts ou estilos inline, use nonces ou hashes para permitir blocos de código específicos.
- Monitore as violações de CSP: Use a diretiva
report-urioureport-topara monitorar as violações de CSP e ajustar sua política de acordo. - Teste completamente: Use o cabeçalho
Content-Security-Policy-Report-Onlypara testar sua política antes de implantá-la em produção. - Iterar e refinar: CSP não é uma configuração única. Monitore e refine continuamente sua política para se adaptar às mudanças em seu aplicativo e no cenário de ameaças.
O que é Cross-Origin Resource Sharing (CORS)?
Cross-Origin Resource Sharing (CORS) é um mecanismo que permite que páginas da web de uma origem (domínio) acessem recursos de uma origem diferente. Por padrão, os navegadores impõem uma Política de Mesma Origem, que impede que scripts façam solicitações para uma origem diferente daquela de onde o script se originou. O CORS fornece uma maneira de relaxar seletivamente essa restrição, permitindo solicitações legítimas de origem cruzada, protegendo contra ataques maliciosos.
Entendendo a Política de Mesma Origem
A Política de Mesma Origem é um mecanismo de segurança fundamental que impede que um script malicioso de um site acesse dados confidenciais em outro site. Uma origem é definida pelo esquema (protocolo), host (domínio) e porta. Dois URLs têm a mesma origem se e somente se tiverem o mesmo esquema, host e porta.
Por exemplo:
https://www.example.com/app1/index.htmlehttps://www.example.com/app2/index.htmltêm a mesma origem.https://www.example.com/index.htmlehttp://www.example.com/index.htmltêm origens diferentes (esquema diferente).https://www.example.com/index.htmlehttps://sub.example.com/index.htmltêm origens diferentes (host diferente).https://www.example.com:8080/index.htmlehttps://www.example.com:80/index.htmltêm origens diferentes (porta diferente).
Como o CORS Funciona
Quando uma página da web faz uma solicitação de origem cruzada, o navegador primeiro envia uma solicitação de "preflight" para o servidor. A solicitação de preflight usa o método HTTP OPTIONS e inclui cabeçalhos que indicam o método HTTP e os cabeçalhos que a solicitação real usará. O servidor então responde com cabeçalhos que indicam se a solicitação de origem cruzada é permitida.
Se o servidor permitir a solicitação, ele inclui o cabeçalho Access-Control-Allow-Origin na resposta. Este cabeçalho especifica a(s) origem(ns) que têm permissão para acessar o recurso. O navegador então prossegue com a solicitação real. Se o servidor não permitir a solicitação, ele não inclui o cabeçalho Access-Control-Allow-Origin e o navegador bloqueia a solicitação.
Cabeçalhos CORS: Uma Olhada Detalhada
O CORS depende de cabeçalhos HTTP para se comunicar entre o navegador e o servidor. Aqui estão os principais cabeçalhos CORS:
- Access-Control-Allow-Origin: Especifica a(s) origem(ns) que têm permissão para acessar o recurso. Este cabeçalho pode conter uma origem específica (por exemplo,
https://www.example.com), um caractere curinga (*) ounull. Usar*permite solicitações de qualquer origem, o que geralmente não é recomendado por motivos de segurança. Usar `null` é apropriado apenas para "respostas opacas", como quando o recurso é recuperado usando o protocolo `file://` ou um URI de dados. - Access-Control-Allow-Methods: Especifica os métodos HTTP que são permitidos para a solicitação de origem cruzada (por exemplo,
GET, POST, PUT, DELETE). - Access-Control-Allow-Headers: Especifica os cabeçalhos HTTP que são permitidos na solicitação de origem cruzada. Isso é importante para lidar com cabeçalhos personalizados.
- Access-Control-Allow-Credentials: Indica se o navegador deve incluir credenciais (por exemplo, cookies, cabeçalhos de autorização) na solicitação de origem cruzada. Este cabeçalho deve ser definido como
truepara permitir credenciais. - Access-Control-Expose-Headers: Especifica quais cabeçalhos podem ser expostos ao cliente. Por padrão, apenas um conjunto limitado de cabeçalhos é exposto.
- Access-Control-Max-Age: Especifica a quantidade máxima de tempo (em segundos) que o navegador pode armazenar em cache a solicitação de preflight.
- Origin: Este é um cabeçalho de solicitação enviado pelo navegador para indicar a origem da solicitação.
- Vary: Um cabeçalho HTTP geral, mas importante para CORS. Quando `Access-Control-Allow-Origin` é gerado dinamicamente, o cabeçalho `Vary: Origin` deve ser incluído na resposta para instruir os mecanismos de cache de que a resposta varia com base no cabeçalho de solicitação `Origin`.
Exemplos Práticos de CORS
Vamos dar uma olhada em alguns exemplos práticos de configurações CORS:
Exemplo 1: Permitindo Solicitações de uma Origem Específica
Esta configuração permite solicitações apenas de https://www.example.com:
Access-Control-Allow-Origin: https://www.example.com
Exemplo 2: Permitindo Solicitações de Qualquer Origem (Não Recomendado)
Esta configuração permite solicitações de qualquer origem. Use com cautela, pois pode introduzir riscos de segurança:
Access-Control-Allow-Origin: *
Exemplo 3: Permitindo Métodos e Cabeçalhos Específicos
Esta configuração permite os métodos GET, POST e PUT e os cabeçalhos Content-Type e Authorization:
Access-Control-Allow-Origin: https://www.example.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: Content-Type, Authorization
Exemplo 4: Permitindo Credenciais
Para permitir credenciais (por exemplo, cookies), você precisa definir Access-Control-Allow-Credentials como true e especificar uma origem específica (você não pode usar * ao permitir credenciais):
Access-Control-Allow-Origin: https://www.example.com
Access-Control-Allow-Credentials: true
Você também precisa definir credentials: 'include' em sua solicitação JavaScript fetch/XMLHttpRequest.
fetch('https://api.example.com/data', {
credentials: 'include'
})
Solicitações de Preflight CORS
Para certos tipos de solicitações de origem cruzada (por exemplo, solicitações com cabeçalhos personalizados ou métodos diferentes de GET, HEAD ou POST com Content-Type de application/x-www-form-urlencoded, multipart/form-data ou text/plain), o navegador envia uma solicitação de preflight usando o método OPTIONS. O servidor deve responder à solicitação de preflight com os cabeçalhos CORS apropriados para indicar se a solicitação real é permitida.
Aqui está um exemplo de uma solicitação e resposta de preflight:
Solicitação de Preflight (OPTIONS):
OPTIONS /data HTTP/1.1
Origin: https://www.example.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: Content-Type, Authorization
Resposta de Preflight (200 OK):
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://www.example.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 86400
O cabeçalho Access-Control-Max-Age especifica por quanto tempo o navegador pode armazenar em cache a resposta de preflight, reduzindo o número de solicitações de preflight.
CORS e JSONP
JSON with Padding (JSONP) é uma técnica mais antiga para contornar a Política de Mesma Origem. No entanto, o JSONP tem riscos de segurança significativos e deve ser evitado em favor do CORS. O JSONP depende da injeção de tags <script> na página, que podem executar código arbitrário. O CORS fornece uma maneira mais segura e flexível de lidar com solicitações de origem cruzada.
Melhores Práticas para CORS
- Evite usar *: Evite usar o curinga (*) no cabeçalho
Access-Control-Allow-Origin, pois ele permite solicitações de qualquer origem. Em vez disso, especifique a(s) origem(ns) específica(s) que têm permissão para acessar o recurso. - Seja específico com métodos e cabeçalhos: Especifique os métodos e cabeçalhos HTTP exatos que são permitidos nos cabeçalhos
Access-Control-Allow-MethodseAccess-Control-Allow-Headers. - Use Access-Control-Allow-Credentials com cautela: Somente habilite
Access-Control-Allow-Credentialsse você precisar permitir credenciais (por exemplo, cookies) em solicitações de origem cruzada. Esteja ciente das implicações de segurança de permitir credenciais. - Proteja suas solicitações de preflight: Garanta que seu servidor lide corretamente com as solicitações de preflight e retorne os cabeçalhos CORS corretos.
- Use HTTPS: Sempre use HTTPS para a origem e os recursos que você está acessando de origem cruzada. Isso ajuda a proteger contra ataques man-in-the-middle.
- Vary: Origin: Se você estiver gerando dinamicamente o cabeçalho `Access-Control-Allow-Origin`, sempre inclua o cabeçalho `Vary: Origin` para evitar problemas de cache.
CSP e CORS na Prática: Uma Abordagem Combinada
Embora o CSP e o CORS abordem preocupações de segurança, eles operam em camadas diferentes e fornecem proteção complementar. O CSP se concentra em impedir que o navegador carregue conteúdo malicioso, enquanto o CORS se concentra em controlar quais origens podem acessar recursos em seu servidor.
Ao combinar CSP e CORS, você pode criar uma postura de segurança mais robusta para seus aplicativos web. Por exemplo, você pode usar o CSP para restringir as fontes de onde os scripts podem ser carregados e o CORS para controlar quais origens podem acessar seus endpoints de API.
Exemplo: Protegendo uma API com CSP e CORS
Digamos que você tenha uma API hospedada em https://api.example.com que você deseja que seja acessível apenas de https://www.example.com. Você pode configurar seu servidor para retornar os seguintes cabeçalhos:
Cabeçalhos de Resposta da API (https://api.example.com):
Access-Control-Allow-Origin: https://www.example.com
Content-Type: application/json
E você pode configurar seu site (https://www.example.com) para usar o seguinte cabeçalho CSP:
Cabeçalho CSP do Site (https://www.example.com):
Content-Security-Policy: default-src 'self'; script-src 'self'; connect-src 'self' https://api.example.com;
Esta política CSP permite que o site carregue scripts e se conecte à API, mas o impede de carregar scripts ou se conectar a outros domínios.
Conclusão
Content Security Policy (CSP) e Cross-Origin Resource Sharing (CORS) são ferramentas essenciais para fortalecer a segurança de seus aplicativos frontend. Ao configurar cuidadosamente CSP e CORS, você pode reduzir significativamente o risco de ataques XSS, ataques de injeção de dados e outras vulnerabilidades de segurança. Lembre-se de começar com uma política restritiva, testar completamente e monitorar e refinar continuamente sua configuração para se adaptar às mudanças em seu aplicativo e no cenário de ameaças em evolução. Ao priorizar a segurança do frontend, você pode proteger seus usuários e garantir a integridade de seus aplicativos web no mundo digital cada vez mais complexo de hoje.