A política de Cross-Origin Resource Sharing (CORS) é um mecanismo fundamental para garantir a segurança e a integridade das aplicações web. Desse modo ela define como os navegadores devem se comportar ao lidar com requisições HTTP entre diferentes origens, ajudando a prevenir ataques maliciosos e protegendo a privacidade dos usuários. Então, aqui no artigo CORS: Seus problemas acabaram exploraremos os conceitos básicos do CORS, suas implicações para o desenvolvimento web e como podemos trabalhar com suas restrições de forma eficaz. Assim caso queira saber detalhes ainda mais específicos recomendo que acesse a documentação Mozilla sobre a temática.
Sumário
O Protocolo HTTP
O protocolo HTTP oferece uma vasta gama de possibilidades dando muita flexibilidade para os servidores e aos clientes. Ocorre que essa flexibilidade pode gerar situações inseguras para os usuários. Por conta disso há políticas para que requisições só serem aceitas pelo servidor dependendo da origem. Veja que o CORS é uma restrição do servidor, portanto o cliente pode implementar características para lidar com ela ou não, independentemente se há o uso de REST, SOAP, etc.
Cross-Origin Resource Sharing
Um serviço HTTP pode restringir quem pode fazer requisições para um dado recurso. Imagine que uma api foi criada e disponibilizada através do endereço https://www.anselme.com.br/minhaapi suportando GET. Eu posso indicar que essa API só seja acessada por clientes cuja origem seja do domínio https://www.anselme.com.br/.
Cross-Origin Resource Sharing ou Compartilhamento de recursos entre origens define o escopo de acesso das requisições. Os parametros Access-Control-Allow faz restrições às requests, e o Access-Control-Allow-Origin restringe especificamente a origem.
HTTP/1.1 403 Forbidden
Date: Wed, 14 Apr 2024 15:00:00 GMT
Server: Apache/2.4.38 (Ubuntu)
Access-Control-Allow-Origin: https://www.anselme.com.br
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 86400
Content-Length: 0
Content-Type: text/plain; charset=utf-8
O exemplo acima especifica a origem, mas profissionais desavisados podem colocar um coringa, como no exemplo abaixo, permitindo todas as origens, logo ignorando essa estrutura de segurança.
access-control-allow-Origin: *
Access-Control-Allow-Methods: *
Access-Control-Allow-Headers: *
Access-Control-Max-Age: 3600
Mas qual o problema? Ou o que é CSRF (Cross-Site Request Forgery)?
O problema é que uma página ao fazer uso de um domínio diferente do que ela pertence: ela pode estar se aproveitando de vulnerabilidades de sistemas. Vou dar um exemplo hipotético. Imagine que uma API de um banco esteja publica disponibilizando transferencias bancárias em GET https://bancofalso.com.br/transferencia. Ela não tem política de CORS e pode ser utilizada assim:
https://bancofalso.com.br/transferencia/{conta-destino}/{valor}
https://bancofalso.com.br/transferencia/12345678/1500,65
Agora, imagine que um atacante envie um link para uma página HTML a uma vítima. O link pode ser http://linkatacante.com.br/link.html. Ao abrir o link uma requisição pode ser feita a API citada acima, fazendo uma transferência indesejada.
Esse ataque pode ser traduzido para Falsificação de solicitação entre sites. É claro que o exemplo é muito simples, mas sites que não têm políticas de CORS são suscetíveis e praticas analogas.
Como o servidor sabe a origem?
O servidor confia no que está escrito na request realizada. Veja a seguir um exemplo de requisição válida:
GET /minhaapi HTTP/1.1
Host: www.anselme.com.br
Origin: https://www.anselme.com.br
Porém isso parece muito falceável. Veja que você pode criar uma aplicação em python que diz que a origem é outra e o servidor vai aceitar. Tudo bem! Isso não é um problema. Qualquer aplicação pode dizer a origem que quiser. Mas, não é assim com os navegadores.
Pois bem, os navegadores modernos não se comportam como qualquer aplicação comum. Eles não permitem que requisições HTTP feitas com XMLHttpRequest ou Fetch API mudem a origem. Na verdade nos navegadores implementam uma política chamada same-origin policy. Ela também é valida para o uso de @font em CSS, texturas WebGL e frames. Em todos esses casos não é possível trocar a origem. Ao invés disso aparecerá um belo erro na tela e no console do navegador.
Simple Requests e Pre-flight Requests
O protocolo indica que há dois tipos de requisição que têm comportamentos diferentes. A primeira são as Simple Requests (requisições simples), que são baseada em verbos GET, POST ou HEAD. Essas requests sempre sofrerão a same-origin policy exigindo a origin correta.
Porém há um segundo cenário, as Pre-flight Requests, quando as requisições usam os verbos PUT, DELETE, CONNECT, OPTIONS, TRACE e PATCH. Ou quando se utilizam alguns headers específicos (Accept, Accept-Language, Content-Language, Content-Type específicos, DPR, Downlink, Save-Data, Viewport-Width ou Width). Ou no caso do Content-Type se o valor for um desses específicos: application/x-www-form-urlencoded, multipart/form-data ou text/plain. Há ainda outras situações mais particulares que você encontrará na documentação do protocolo.
Bom, nesse segundo cenário é obrigatório que inicialmente se faça um OPTIONS indicando o desejo de fazer a requisição para aquela origem. Se a origem for aceita o servidor dará uma resposta com Allow Origin. Após isso, requisições poderão ser feitas diretamente tendo o limite de tempo definido por Access-Control-Max-Age.
CORS: Seus problemas acabaram? Onde?? Porque, então, continua sendo um problema para mim!?
Pois bem, saber de tudo isso não faz deixar de ser uma questão a ser trabalhada. Por exemplo, digamos que você esteja criando um projeto de front end que deve consumir APIs para mostrar seus resultados na sua aplicação Angular 14. Se ela tem exigência de CORS você não conseguirá fazer as requisições na máquina de desenvolvimento. Portanto só conseguirá ver os resultados se implantado em produção. Terrível!
Mock Server
No mercado há vários aplicativos que fazem mocks para requisições http. Alguns exemplos: JSON Server, Mockoon, WireMock, Postman Mock Server, MockServer, etc. Como utilizar:
- Para acessar um recurso protegido por CORS;
- Para acessar um recurso que não está funcionando, mas você sabe qual é o retorno esperado;
- Para acessar um recurso sem ter que efetivamente tocar o servidor; etc;
Pois bem, o Wiremock é a solução que escolhemos para esse cenário. Você pode instalar diretamente em java, utilizar o SaaS dele ou instalar através do docker. Entre na documentação do produto para mais detalhes. Aqui no artigo você pode ver o seu uso via docker.
docker run -it --rm -p 8080:8080 --name wiremock wiremock/wiremock:3.5.2
Após instalado você pode usar o postman, insomnia, etc. para fazer uma requisição para o WireMock. Ele possui uma rota para http://localhost:8080/_admin/mappings/new onde você indica um formato de request e uma response esperada. Com isso você pode montar todas as requisições bloqueadas por CORS para seu uso.
Minha preferida: Plugin Cors
Há uma outra solução que não funciona para todos os casos mas é infinitamente mais simples: Ela se chama Test CORS ou Allow CORS: Access-Control-Allow-Origin. Trata-se de um plugin do Chrome ou semelhantes, assim, quando ele estiver ligado sua aplicação web vai fazer requisições para locais que têm restrições de CORS e pronto. “Très bien!”. Link para o plugin.
Ao clicar no botão ‘C’ ele fica colorido e as restrições de CORS param de afetar seu navegador. Quando ele estiver desligado, o comportamento é o esperado. Isso pode ser muito útil nos cenários cuja restrição seja apenas o CORS. Quando ele não for suficiente, desbrave o mock server.
Conclusão de CORS: Seus problemas acabaram
Em conclusão ao artigo CORS: Seus problemas acabaram, compreender e aplicar corretamente as políticas de CORS é essencial para o desenvolvimento de aplicações web seguras e eficientes. Ao seguir as diretrizes do CORS, os desenvolvedores podem garantir que suas aplicações sejam acessíveis apenas a partir de origens confiáveis, protegendo assim contra possíveis vulnerabilidades e ataques. Além disso, o uso de ferramentas como mock servers pode facilitar o desenvolvimento e teste de aplicações que requerem interações com diferentes origens. Assim, ao adotar boas práticas de segurança e implementação do CORS, os desenvolvedores podem criar aplicações web mais robustas e confiáveis.
Ele atua/atuou como Dev Full Stack C# .NET / Angular / Kubernetes e afins. Ele possui certificações Microsoft MCTS (6x), MCPD em Web, ITIL v3 e CKAD (Kubernetes) . Thiago é apaixonado por tecnologia, entusiasta de TI desde a infância bem como amante de aprendizado contínuo.