CORS, XSS e CSRF com exemplos em 10 minutos
Este artigo deve ser o seu ponto de entrada para os padrões de segurança web existentes, os ataques web mais comuns e os métodos para preveni-los. No final, você também vai descobrir como e porque Samy foi o herói de todos (exceto Rupert Murdoch, acho eu)
Cross-origin resource sharing, ou CORS, é recurso de segurança do IE10+, Chrome 4+, Firefox 3.5+ ou quase todas as versões do navegador lançadas após 2012, exceto o Opera Mini.
Quando CORS são configurados no servidor que está disponível no domínio website.com
então os recursos desse domínio que são solicitados através de AJAX devem ser iniciados a partir de ativos que são servidos a partir desse mesmo domínio.
Por outras palavras, se activarmos CORS em domain-b.com
e o configurarmos para permitir apenas GET
pedidos do domínio domain-b.com
então se quiser usar a imagem disponível sob https://domain-b.com/images/example.png
em tela no seu website que está alojado em domain-a.com
, então essa imagem não será carregada para a maioria dos seus visitantes.
Os seus recursos protegidos por CORS ainda estarão disponíveis quando solicitados por qualquer ferramenta ou navegador que não respeite CORS policy
.
configuração CORS
CORS estão desativados por padrão, o que significa que não há um manipulador de servidor adequado que irá configurar CORS, o que significa que você não pode acessar recursos de origem diferente no seu XHR. Basicamente, se você não fizer nada ou habilitar especificamente CORS apenas para domínios específicos, então qualquer pedido AJAX tentando acessar seus recursos será rejeitado porque os navegadores da web são respeitosos com o CORS policy
.
Esta é a razão pela qual você encontra o problema CORS quando você começa a desenvolver SPA usando VueJS e NodeJS. Sua aplicação VueJS está hospedada em http://localhost:8080
e quando você tenta acessar a aplicação do servidor NodeJS em http://localhost:8000
você recebe “No Access-Control-Allow-Origin header is present
” porque esses são dois diferentes ORIGINS
(combinação de PROTOCOL
, HOST
e PORT
).
Cool fix for CORS issue in VueJS development mode is to set devServer proxy in your vue.config.js
file as follows:
module.exports = { ... devServer: { proxy: 'http://localhost:8000', }, ...}
To set CORS in production you should add appropriate listenener for OPTIONS
request. Esse ouvinte deve enviar resposta 200
com no body
mas com Headers
que irá definir a sua política de CORS desejada:
Access-Control-Allow-Origin: https://domain-b.comAccess-Control-Allow-Methods: GET
Para mais informações sobre como configurar CORS verifique https://enable-cors.org/index.html, e para mergulhar mais fundo em CORS policy
verificar https://livebook.manning.com/book/cors-in-action/part-1/
XSS
XSS significa Cross Site Scripting e é o tipo de ataque de injecção. É listado como 7ª das 10 principais vulnerabilidades identificadas pela OWASP em 2017. Cross site scripting é o método onde o atacante injecta o script malicioso em um site confiável.(seção atualizada, obrigado Sandor) Existem 3 tipos de ataques deste tipo.
- XSS armazenado – Vulnerabilidade vinda de entradas de usuários desprotegidos e não higienizados – Vulnerabilidade vinda de valores desprotegidos e não higienizados de URLs que são usados diretamente em páginas web
- XSS baseado em DOM – Similar ao XSS refletido, valores desprotegidos e não higienizados de URLs usadas diretamente em páginas web, com a diferença de que o XSS baseado em DOM nem sequer vai para o lado do servidor
Ataque
1. XSS armazenado
Aqui é um exemplo de ataque. O atacante vem em seu site e encontra campo de entrada desprotegido como campo de comentário ou campo de nome de usuário e insere script malicioso ao invés do valor esperado. Depois disso, sempre que esse valor for exibido para outros usuários, ele executará o código malicioso. O script malicioso pode tentar acessar sua conta em outros sites, pode ser o envolvido no ataque DDoS ou similar. Representação visual(source geeksforgeeks.org):
2. Reflected XSS
Reflected XSS é um ataque que acontece quando o atacante descobre uma página com tal vulnerabilidade, por exemplo:
URL esperada: https://mywebpage.com/search?q=javascript
URL malicioso: https://mywebpage.com/search?q=<script>alert('fortunately, this will not work!')</script>
<body>...<div> showing results for keyword <script> document.write(window.location.href.substr(window.location.href.indexOf('q=') + 2))</script></div>......JavaScript results......</body>
Após a descoberta, o atacante isca o usuário para clicar em tal URL maliciosa e voilá. Os dados sensíveis do usuário são explorados.
Ciclo de vida de ataque ilustrado no exemplo fornecido por geekforgeeks.com:
3. DOM baseado em XSS
Este tipo de ataque é o mesmo que o refletido, mas com a diferença que parte maliciosa URL
não será enviada para o servidor. Por exemplo acima:
URL esperada: https://mywebpage.com/search?q=javascript
URL malicioso(reflectido XSS): https://mywebpage.com/search?q=<script>alert('fortunately, this will not work!')</script>
URL malicioso(XSS baseado em DOM): https://mywebpage.com/search#q=<script>alert('fortunately, this will not work!')</script>
Diferença está no caractere #
sendo usado ao invés de ?
. Os navegadores não enviam parte da URL após # para o servidor, então eles a passam diretamente para o seu código cliente.
Proteção
Todos os valores que podem ser inseridos pelo usuário e são usados em seu aplicativo (tanto no lado do servidor quanto no lado do cliente) devem ser tratados como dados não confiáveis e, portanto, devem ser processados antes de serem usados! Você deve fazer uma verificação de segurança na sua aplicação servidor e na sua aplicação cliente, bem como!
Como mostrado na documentação VueJS por si só escapa da string antes de obter valor da variável. Versões mais recentes do Angular também escapam de strings implicitamente, então se você estiver usando Vanilla JS, JQuery ou similar você deve implementar o escape de strings manualmente.
Existem três abordagens mais comuns no processamento de dados não confiáveis são listadas abaixo e o método ideal depende do tipo real do campo que você precisa processar.
1. validação de strings
Validação é o método onde o usuário define um conjunto de regras, e exige dados não confiáveis para satisfazer essas regras antes de seguir em frente. Este método é bom para valores numéricos, nome de usuário, e-mail, senha e campos similares com conjunto concreto de regras de sintaxe.
Cheque bibliotecas existentes para o seu framework antes de considerar escrever validadores pelo seu próprio.
2. String escape
O método escape é útil para casos em que você deve habilitar o usuário a usar sinais de pontuação. Este método passa por string e procura por caracteres especiais, tais como <
>
e substitui-os pelo nome da entidade de caracteres HTML apropriada. Aqui está uma função básica que você poderia usar:
function escapeText(text) { return text.replace(/&/g, '&') .replace(/</g, '<') .replace(/>/g, '>') .replace(/"/g, '"')}
Again, verifique as bibliotecas existentes antes de escrever a sua própria.
3. Sanitização de strings
Sanitização de strings é usada quando o usuário tem permissão para inserir algumas tags HTML em seus comentários, artigos ou similares. O método de sanitização passa pelo texto e procura por tags HTML que você especifica e as remove. Uma das bibliotecas mais populares que usa esta abordagem é o Google Closure.
Este método é caro e considerado prejudicial, portanto faça mais pesquisas antes de escolhê-lo.
Navegadores web (sem fontes disponíveis desde que versão, o IE corrigiu este problema em 2014.) escapam automaticamente das URLs antes de enviá-las para o lado do servidor e torná-las disponíveis em window.location
objeto também, portanto o 2º e 3º tipo de ataque estão aqui apenas para estar ciente delas e para deixar claro que os parâmetros de URL também devem ser tratados como dados não confiáveis.
Para informações mais detalhadas sobre XSS e como proteger corretamente sua aplicação se você girar muitos dados não confiáveis, por favor verifique a planilha OWASP sobre prevenção de XSS.
CSRF
Cross site request forgery ou CSRF é um tipo de ataque que ocorre quando um site, e-mail, blog, mensagem instantânea ou programa malicioso faz com que o navegador web de um usuário execute uma ação indesejada em outro site confiável onde o usuário é autenticado. Essa vulnerabilidade é possível quando o navegador envia automaticamente um recurso de autorização, como um cookie de sessão, endereço IP ou similar a cada solicitação.
ATTACK
Vamos supor que o usuário está conectado ao seu aplicativo web da bolsa de valores desprotegido e que você está usando um cookie de sessão ou cookie JWT para autenticação. O atacante também usa o seu serviço e é capaz de verificar como a sua API funciona. O atacante engana o usuário para executar o script (clicando no link SPAM no e-mail ou similar) que enviará o pedido para a sua API https://www.stockexchange.com/users/withdraw?how_much=all&address=MY_ADDRESS
(design terrível da API, não pergunte). Como a requisição é executada a partir do navegador que envia a carga útil de autenticação com cada requisição, seu servidor web stockexchange autenticará o usuário com sucesso e executará a transação e o usuário enganado perderá todo o seu saldo sem mesmo estar ciente disso porque tudo aconteceu em segundo plano. Representação visual(fonte miro.medium.com)
PROTECÇÃO
Felizmente existem padrões fáceis de implementar que previnem estes ataques web. Um dos padrões mais comuns é o uso de CSRF token
. Basicamente o procedimento é o seguinte:
- Gerar token único para o pedido de cada usuário, assim chamado
CSRF token
. - Armazená-lo com segurança no servidor e enviá-lo de volta ao usuário como payload de resposta.
- Armazená-lo
CSRF token
no lado do cliente. - Quando o usuário tenta executar qualquer requisição de mudança de estado* envie que
CSRF token
com requisição como carga útil. - Antes de executar essa requisição no lado do servidor verifique se
CSRF token
está presente e é válida.
Esta é a maneira mais fácil de prevenir ataques CSRF para todos os usuários.
Se você está lidando apenas com visitantes que usam navegadores modernos, então você pode confiar no atributo SameSite
cookie de sessão.(thanks Gergely)
As respostas do servidor são processáveis na resposta XHR, então não há proteção contra ataque CSRF se a sua aplicação web for vulnerável ao XSS!
Para mergulhar mais fundo verifique o OWASP no CSRF.
BONUS
Documentário curto sobre Samy, autor do worm que derrubou o MySpace em 2005 abusando da vulnerabilidade do XSS, passando a defesa do CSRF do MySpace.
https://youtu.be/DtnuaHl378M
Mais informações sobre o worm do Samy
https://samy.pl/myspace/tech.html