# Entenda CORS de uma vez por todas!

> Guia definitivo sobre CORS: o que é, como funciona e como resolver erros de Cross-Origin Resource Sharing. Segurança web completamente explicada. Domine!

URL: https://dpw.dev/miscelanea/cors/  
Publicado em: 2020-08-07  
Categoria: miscelanea  
Tags: basico-da-web, seguranca  
Autor: Tárcio Zemel

Não precisa disfarçar: eu sei que você já deu de cara com algum erro de **CORS** no seu console enquanto trabalhava em um projeto Web. 😬

> Artigo baseado em [CS Visualized: CORS](https://dev.to/lydiahallie/cs-visualized-cors-5b8h).

Se você nunca entendeu bem esse negócio de CORS, mesmo quando procurou algum material de explicação, seus problemas acabaram: neste artigo, aprenda de uma vez por todas **o que é CORS**, qual sua razão de existir e por que CORS é amigo de todos os devs (e pessoas normais).

No dia-a-dia do desenvolvimento front end, é bastante comum ser preciso exibir dados localizados em outro lugar. Mas, antes de ser possível exibir esses dados, o navegador precisa fazer uma requisição a um servidor para buscar esses dados; o cliente envia uma requisição HTTP com todas as informações que o servidor precisa para retornar esses dados ao cliente.

Digamos que se está tentando buscar algumas informações no site `www.mywebsite.com` de um servidor localizado em `api.website.com`.

![Animação com exemplo de uma requisição simples de dados em um subdomínio.](/images/blog/cors/qyeikeonofi8dfl0jz2t.gif)

Este é um exemplo simples de envio de uma solicitação HTTP para um servidor, que respondeu com dados JSON solicitados.

Agora, exatamente a mesma solicitação, mas de outro domínio. Em vez de fazer a solicitação em `www.mywebsite.com`, vai ser de um site de URL `www.anotherdomain.com`.

![Animação mostrando uma requisição de dados em outro domínio que ocasionou um erro de CORS.](/images/blog/cors/lxhuh29biuwhefs3k9d9.gif)

O quê?! Foi enviada exatamente a mesma requisição, mas, desta vez, o navegador mostrou um erro estranho? 🤔

Isso foi **CORS** em ação.

Chega o momento de examinar o porquê desse erro ter ocorrido e o quê exatamente ele significa.

## Same-Origin Policy

Há algo na Web chamado **Same-Origin Policy** (ou **Política de Mesma Origem**). Por padrão, só é possível acessar recursos localizados na mesma origem que a origem de um solicitação. Não há problema em carregar uma imagem localizada em `https://mywebsite.com/image1.png`, por exemplo.

Entretanto, um recurso tem "origem cruzada" (_cross-origin_) quando está localizado em um (sub)domínio, protocolo ou porta diferente.

![Explicação de em quais situações um recurso é considerado original, same origin e cross origin.](/images/blog/cors/ibyoyo1yqta9cdvh0tbv.webp)

Legal, mas... Por que, afinal, essa política de mesma origem (_same-origin_) existe?

Digamos que essa política de mesma origem não existisse e você clicou acidentalmente em um dos muitos links de vírus que sua tia envia no Facebook.

Esse link o redireciona para um "site maligno" que possui um iframe incorporado que carrega o site do seu banco e efetua login com sucesso com alguns cookies definidos.

Os desenvolvedores deste "site maligno" tornaram possível o site acessar esse iframe e interagir com o conteúdo do DOM do site do seu banco para enviar dinheiro para uma outra conta!

![Animação esquemática de uma fraude bancária a partir de um site falso.](/images/blog/cors/50nmgrnkf6pb6gphno06.gif)

Não é preciso falar mais nada; este é um enorme risco de segurança!

E é exatamente aqui que a política de mesma origem vem para ajudar. Essa política garante que apenas seja possível acessar recursos — adivinhe — **da mesma origem** (_same-origin_).

![Animação mostrando como a política de mesma origem da Web ajuda a evitar fraudes.](/images/blog/cors/8unei9l9enunbpr58o54.gif)

Nesse exemplo, o site `www.evilwebsite.com` tentou acessar recursos de origem cruzada no site `www.bank.com`. A política de mesma origem impediu que isso acontecesse, garantindo que os desenvolvedores do "site maligno" não conseguissem acessar os dados bancários.

Entendido, mas... **O que isso tem a ver com CORS?**

## Client-side CORS

Embora a política de mesma origem (_same-origin policy_) realmente se aplique apenas a scripts, os navegadores estenderam essa política para solicitações JavaScript: _por padrão, só é possível acessar recursos da mesma origem._

![Animação mostrando várias requisições diferentes e como a política de mesma origem afeta cada uma delas.](/images/blog/cors/0qe4yzasvrm7r0a76kui.gif)

É bastante comum no dia-a-dia de desenvolvimento ser preciso acessar recursos de origem cruzada — um exemplo trivial é o front-end precisar interagir com uma API de back-end para pegar alguns dados.

Para permitir solicitações de origem cruzada com segurança, o navegador usa um mecanismo chamado... CORS!

**CORS** significa **Cross-Origin Resource Sharing** (ou **Compartilhamento de Recursos de Origem Cruzada**). Embora o navegador impeça o acesso de recursos que não estão localizados na mesma origem, é possível usar o CORS para alterar um pouco essas restrições de segurança e ainda garantir que este acesso seja feito com segurança.

_User Agents_ (um navegador, por exemplo) podem usar CORS para permitir solicitações de origem cruzada — que, de outra forma, teriam sido bloqueadas — com base nos valores de determinados cabeçalhos específicos de CORS em uma resposta HTTP.

Quando uma requisição cross-origin é feita, o cliente automaticamente adiciona um cabeçalho extra à solicitação HTTP: `Origin`. O valor desse `Origin` é a origem de onde a solicitação partiu.

![Animação mostrando a inserção automática do cabeçalho Origin em uma requisição CORS.](/images/blog/cors/91qh9mo3q5lcl0ng4t0r.gif)

Para que o navegador permita acessar recursos de origem cruzada, ele espera certos cabeçalhos da resposta do servidor, que especificam se esse servidor permite solicitações de origem cruzada (ou não).

## Server-side CORS

Devs responsáveis pelo back-end podem garantir que solicitações de origem cruzada sejam permitidas, adicionando cabeçalhos extras à resposta HTTP — que começam com `Access-Control-*`.

Com base nos valores desses cabeçalhos de resposta (_response headers_) de CORS, o navegador agora pode permitir determinadas respostas de origem cruzada que normalmente seriam bloqueadas pela política de mesma origem.

Embora existam [diversos cabeçalhos de CORS](https://fetch.spec.whatwg.org/#http-responses), há um cabeçalho que o navegador necessariamente precisa para permitir o acesso a recursos de origem: `Access-Control-Allow-Origin`.

O valor desse cabeçalho especifica **quais origens têm permissão para acessar os recursos** solicitados do servidor.

Por exemplo, em um servidor ao qual `https://mywebsite.com` deve ter acesso, é possível adicionar o valor desse domínio ao cabeçalho `Access-Control-Allow-Origin`.

![Animação mostrando o uso do cabeçalho CORS Access-Control-Allow-Origin.](/images/blog/cors/bpw6vwe6w5tm3cadqg7j.gif)

Este cabeçalho é adicionado à resposta que o servidor envia de volta ao cliente. Ao adicionar esse cabeçalho, **a política de mesma origem não impede mais de receber recursos** localizados na origem `https://api.mywebsite.com` quando se envia a requisição em `https://mywebsite.com`.

![Animação mostrando exemplo de correta configuração de política de mesma origem para CORS.](/images/blog/cors/akf0epavr00o2vo857lc.gif)

O mecanismo CORS no navegador verifica se o valor do cabeçalho `Access-Control-Allow-Origin` é igual ao valor do `Origin` enviado pela requisição.

Nesse exemplo, a origem da solicitação é `https://www.mywebsite.com`, que está listada no cabeçalho de resposta `Access-Control-Allow-Origin`.

![Animação exemplificando requisição feita com sucesso sob uma configuração de CORS feita com sucesso.](/images/blog/cors/foathske6a5prjf02dyf.gif)

Maravilha! Agora é possível receber com êxito os recursos de origem cruzada (_cross-origin resources_)!

Mas o que acontece quando se tenta acessar esses recursos de uma origem que não está listada no cabeçalho `Access-Control-Allow-Origin`?

![Animação exemplificando requisição falhada devido a uma requisição feita fora da configuração de CORS.](/images/blog/cors/lqtoobekf1h1d08lcl56.gif)

Ahh, sim: acontece aquele erro de CORS (que às vezes pode ser tão frustrant). Mas, agora, você finalmente entendeu que faz todo o sentido!

```
The 'Access-Control-Allow-Origin' header has a value
 'https://www.mywebsite.com' that is not equal
to the supplied origin.
```

Nesse exemplo, a origem fornecida foi `https://www.anotherwebsite.com`; no entanto, o servidor não tinha essa origem fornecida na lista de origens permitidas no cabeçalho `Access-Control-Allow-Origin`. O CORS bloqueou a solicitação com êxito e não foi possível acessar os dados.

> **Atenção:** O CORS também permite adicionar o curinga `*` como o valor para as origens permitidas. Isso significa que solicitações de todas as origens devem ter acesso aos recursos solicitados, portanto, tenha cuidado!

### Access-Control-Allow-Methods

`Access-Control-Allow-Origin` é somente um dos muitos cabeçalhos CORS possíveis. É possível estender as políticas CORS do servidor para permitir/proibir certas solicitações.

Outro cabeçalho comum é o `Access-Control-Allow-Methods`. Através dele, o CORS só permitirá solicitações de origem cruzada se elas forem enviadas com um dos métodos listados.

![Animação exemplificando o uso do cabeçalho CORS Access-Control-Allow-Methods.](/images/blog/cors/yjjhg7yr3kjrh1nm44mo.gif)

Neste exemplo, somente solicitações de método `GET`, `POST` ou `PUT` serão permitidas; outros métodos (como `PATCH` ou `DELETE`), bloqueados.

> **Nota:** Se estiver curioso para saber quais são os outros possíveis cabeçalhos do CORS e para que são usados, [confira essa lista](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#The_HTTP_response_headers).

E por falar em requisições `PUT`, `PATCH` e `DELETE`, CORS realmente lida com elas de maneira diferente. Essas solicitações "não simples" iniciam algo chamado _preflight request_.

## Preflighted Requests

CORS possui 2 tipos de requisição: **simple request** (_pedido simples_) e **preflighted** ("_pré-confirmada_", "_pré-comprovada_" ou algo assim). Se uma solicitação é _simple_ ou _preflighted_, depende de alguns valores dentro da própria requisição.

Uma solicitação é simple quando a requisição é um método `GET` ou `POST` e não possui cabeçalhos personalizados. Qualquer outra, como requisições `PUT`, `PATCH` ou `DELETE`, será preflighted.

> **Nota:** Confira [essa lista](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#Simple_requests) para saber os requisitos necessários de uma requisição para ser considerada _simple_.

Mas o que realmente significa uma requisição "preflighted" e por que isso acontece?

Antes de uma requisição ser realmente enviada, o cliente gera uma requisição preflighted que contém informações sobre a solicitação real nos cabeçalhos `Access-Control-Request-*`.

Isso fornece informações ao servidor sobre a solicitação real que o navegador está tentando fazer: qual é o **método**, quais são os **cabeçalhos adicionais** e assim por diante.

![Animação exemplificando uma requisição preflighted.](/images/blog/cors/pp30p7ej496f8bqta4he.gif)

O servidor recebe essa solicitação preflighted e envia uma resposta HTTP vazia de volta com os cabeçalhos CORS do servidor. O navegador recebe a resposta de comprovação (_preflight response_) — que não contém quaisquer dados além dos cabeçalhos CORS — e verifica se a solicitação HTTP deve ser permitida.

![Animação exemplificando o fluxo completo de uma requisição e resposta preflighted.](/images/blog/cors/py19auar8xhs933ilmsc.gif)

Então, o navegador envia a solicitação real ao servidor, que responde com os dados solicitados.

![Animação exemplificando retorno de dados do servidor após uma requisição preflighted de sucesso.](/images/blog/cors/pfv1dcg77yjxbue5ryzf.gif)

Entretanto, se não for o caso, o CORS bloqueará a solicitação preflighted e a solicitação real nunca será enviada.

A preflighted request é uma ótima maneira de impedir o acesso ou a modificação de recursos em servidores que não possuem nenhuma política CORS ativada (ainda).

Com isso, os servidores ficam protegidos contra solicitações de origem cruzada indesejadas (_unwanted cross-origin requests_).

> **Dica:** Para reduzir o número de viagens de ida e volta ao servidor, é possível armazenar em cache as respostas preflighted com um cabeçalho `Access-Control-Max-Age` às solicitações CORS.

## Credenciais

Cookies, cabeçalhos de autorização e certificados TLS são definidos por padrão apenas em solicitações de mesma origem (_same-origin requests_). No entanto, pode ser preciso usar essas credenciais em solicitações cross-origin — por exemplo, incluir cookies na requisição que o servidor usa para identificar algum usuário.

Embora o CORS não inclua credenciais por padrão, é possível usar o cabeçalho `Access-Control-Allow-Credentials`.

Se for preciso incluir cookies e/ou outros cabeçalhos de autorização em cross-origin requests, define-se o campo `withCredentials` como `true` na solicitação e o cabeçalho `Access-Control-Allow-Credentials` à resposta.

![Animação mostrando o uso de credenciais em requisição/resposta ao/do servidor.](/images/blog/cors/vg3yo6qfqw12oh0f68yg.gif)

Com isso, é possível incluir credenciais em requisições cross-origin. 🥳

## Conclusão

Erros de CORS às vezes podem ser frustrantes, mas é incrível que essa tecnologia permita fazer solicitações de origem cruzada (_cross-origin requests_) com segurança através do navegador.

Depois de ter lido nosso artigo, com certeza suas principais dúvidas sobre o funcionamento básico de CORS agora foram esclarecidas de uma vez por todas!

Mas, obviamente, há muito mais sobre **CORS** do que aqui consta. Se tiver interesse em estudar mais sobre o assunto, [existem muitos bons recursos por aí](https://livebook.manning.com/book/cors-in-action/part-1/) ([inclusive da própria W3C](https://www.w3.org/wiki/CORS_Enabled)).

---

Fonte: [dpw - desenvolvimento para web](https://dpw.dev/) (pt-BR).
Guia para agentes: https://dpw.dev/llms.txt
Índice completo: https://dpw.dev/sitemap-index.xml
Feed: https://dpw.dev/rss.xml
