O que é CORS e como resolver os principias erros

O CORS (Cross-origin Resource Sharing) é um mecanismo utilizado pelos navegadores para compartilhar recursos entre diferentes origens. O CORS é uma especificação do W3C e faz uso de headers do HTTP para informar aos navegadores se determinado recurso pode ser ou não acessado.

Para compreender melhor, imagine que você está desenvolvendo uma aplicação web que consiste em uma SPA e uma API. Tudo ocorre sem problemas no seu ambiente local, mas ao fazer o deploy em produção você se depara com isso:

Erro de CORS

Isso acontece devido a um mecanismo de segurança presentes nos navegadores chamado de same-origin policy. Ele é usado para limitar como um documento ou script de uma origem pode interagir com recursos de outra origem.

HTTP - Fundamentos
Curso de HTTP - Fundamentos
CONHEÇA O CURSO

Entenda como origem a combinação entre o protocolo (http ou https), o host (painel.treinaweb.com.br) e a porta (80 ou 443, podendo ser omitida) de um determinado endereço (http://painel.treinaweb.com.br/). Se a origem de duas URLs forem idênticas, a interação entre esses recursos pode acontecer sem problema.

Por exemplo, considere a seguinte URL: http://painel.treinaweb.com.br/perfil/. Alguns exemplos de URLs com same-origin considerando a origem são http://painel.treinaweb.com.br/ e http://painel.treinaweb.com.br/cursos/. Nesses casos a única alteração está no path, com o início da URL igual.

Agora, as seguintes URLs seriam bloqueadas: https://painel.treinaweb.com.br/perfil/, http://painel.treinaweb.com.br:81/perfil/index.html, http://www.treinaweb.com.br/. No primeiro caso, o protocolo é diferente (https), no segundo caso temos outra porta e, por fim, o subdomínio do host é diferente.

Em todos esses casos você está sujeito a uma requisição controlada por CORS:

Conceitos de CORS

Possíveis erros de CORS

Como a utilização e compartilhamento de recursos de origens diferentes é algo bastante comum na internet, nem tudo que o navegador precisa carregar está sujeito ao same-origin policy. Sua página está sujeita a algum tipo de problema de CORS em requisições como:

Os casos mais comuns são com as requisições javascript que utilizam XMLHttpRequest ou Fetch APIs. Para esses casos vamos entender como o CORS funciona e como podemos solucionar corretamente esse problema.

JavaScript Avançado
Curso de JavaScript Avançado
CONHEÇA O CURSO

Ciclo de uma requisição com CORS

Ao enviar uma requisição para uma origem diferente, o navegador utiliza de um header específico enviado pelo servidor chamado Access-Control-Allow-Origin. A partir desse e mais alguns headers o navegador determina se aquele recurso será carregado ou não.

Em alguns tipos de requisições, é necessário enviar uma requisição preliminar chamada de preflighted request. O preflighted request utiliza o método OPTIONS do HTTP informando o método e domínio que será invocado para assim garantir que a requisição seguinte pode ser realizada.

Temos abaixo um diagrama que mostra como funciona uma requisição que precisa enviar uma chamada de preflight:

Fluxo de preflight request

Como resolver problemas de CORS

Quando encontramos um erro de CORS, é importante verificar qual requisição esta causando esse problema diretamente no console do seu navegador. Geralmente o problema é causado pela ausência de headers no lado do servidor.

Para corrigir esse problema, garanta que o servidor está enviando os seguintes headers na sua resposta:

Access-Control-Allow-Origin: https://perfil.treinaweb.com.br
Access-Control-Allow-Methods: POST, GET
Access-Control-Allow-Headers: *
Access-Control-Max-Age: 86400

Nesse exemplo, estamos permitindo que a origem https://perfil.treinaweb.com.br acesse os recursos daquele servidor, sendo possível o uso dos métodos HTTP GET e POST, juntamente com qualquer header adicional. Para os casos de preflight request, temos também o header Access-Control-Max-Age que funciona como um cache, em segundos, para essa request.

Tenha uma atenção especial ao header Access-Control-Allow-Origin. Você pode utilizar * como sua origin ou até em partes dela (https://*.treinaweb.com.br por exemplo, para incluir todos os subdomínios da TreinaWeb), mas tente sempre limitar para origens conhecidas da sua aplicação, evitando assim que origens desconhecidas acessem seus servidores.

Como enviar esses headers vai variar dependendo da linguagem ou servidor da sua aplicação. Como por exemplo, com express você pode definir os headers necessários usando um middleware de CORS:

var express = require('express')
var cors = require('cors')
var app = express()

app.use(cors())

app.get('/products/:id', function (req, res, next) {
  res.json({msg: 'This is CORS-enabled for all origins!'})
})

app.listen(80, function () {
  console.log('CORS-enabled web server listening on port 80')
})

Caso você não tenha acesso ao código da sua aplicação, você pode configurar seu servidor web, como o Apache, para retornar esses headers:

Header set Access-Control-Allow-Origin "*"

Em outros casos, pode ser configurar o serviço que você está consumindo, como o S3 da Amazon. Esses serviços podem ser configuráveis com regras específicas para atender esses casos, porém isso varia de serviço a serviço.

Conclusão

Nesse artigo conhecemos o que significa de fato o CORS e como podemos resolver esses tipos de problemas. Existem algumas outras configurações que podem ser feitas para implementar o CORS nas suas aplicações, como o suporte a requests com credentials que não abordamos aqui.

Para saber mais, temos uma excelente referência da Mozilla que explica em detalhes como funciona o CORS.

Deixe seu comentário

Autor dos cursos de cloud computing da TreinaWeb. Graduado em Gestão de TI pela FATEC e quase bacharel em Sistemas de Informação pela UFSCar. Tem experiência em desenvolvimento backend com PHP, mas se encontrou trabalhando com DevOps. Microsoft Certified: DevOps Engineer Expert, Azure Solutions Architect Expert e Azure Data Engineer Associate, AWS Certified Solutions Architect - Associate, e Zend Certified Engineer (ZCE). @gmsantos

© 2004 - 2019 TreinaWeb Tecnologia LTDA - CNPJ: 06.156.637/0001-58 Av. Paulista, 1765, Conj 71 e 72 - Bela Vista - São Paulo - SP - 01311-200