Saiba a diferença entre solicitação HTTP simples e XHR.
Aplicativo Web Origin - https://github.com
Quando você abre um site digitando Origin Web App, seu navegador faz solicitações HTTP simples. CORS não é aplicável aqui. Como estamos solicitando voluntariamente a veiculação de conteúdo do Origin Web App. Seu navegador irá/deverá atendê-lo sem problemas. Mas, quando se trata de solicitações XHR, o JavaScript carregado pelo Origin Web App em seu navegador pode fazer uma solicitação a qualquer servidor (https://netflix.com) solicitando um recurso. Agora, o Origin Web App é propriedade do Github, mas https://netflix.com é propriedade da Netflix, esse servidor pode servir qualquer coisa. O Github não pode assumir o controle de um servidor pertencente à Netflix. Isso tem muitas implicações de segurança, potencialmente roubando conteúdo de um site (pode ser um site financeiro) para qualquer servidor remoto.
Felizmente, o CORS resolve esse problema muito bem com um determinado conjunto de regras.
É um padrão definido pelo W3C para permitir solicitações de origem cruzada entre o cliente (navegador) e o servidor para compartilhar recursos ao mesmo tempo, mantendo a segurança. Qualquer navegador cumprirá esses padrões para evitar o carregamento de recursos de servidores de terceiros.
Um cabeçalho indica a origem de uma solicitação. É enviado com solicitações CORS, bem como com solicitações POST.
Sintaxe:
Origin: <scheme> "://" <hostname> [":" <port> ]
Exemplos:
Origin: https://netflix.com
Origin: http://netflix.com:443
Origin: http://localhost:1443
Este cabeçalho é usado pelo navegador ao emitir solicitações pré-voo para indicar qual método de solicitação será usado quando a solicitação real for feita.
Sintaxe:
Access-Control-Request-Method: <method>
<method>
pode ser GET
, POST
ou DELETE
.
Exemplo:
Access-Control-Request-Method: POST
Este cabeçalho é novamente usado nas solicitações pré-voo pelo navegador para indicar quais cabeçalhos de solicitação serão usados quando a solicitação real for feita. Para usar vários cabeçalhos, eles devem ser separados por vírgula.
Sintaxe:
Access-Control-Request-Headers: <header-name>
Access-Control-Request-Headers: <header-name>, <header-name>
Exemplo:
Access-Control-Request-Headers: X-PINGOTHER, Content-Type
Importante: todo o cabeçalho deve estar na lista segura do CORS ou ser um cabeçalho personalizado como X-Custom-Header
.
Accept
Accept-Language
Content-Language
Content-Type
Os valores permitidos são application/x-www-form-urlencoded
, multipart/form-data
e text/plain
.
Os cabeçalhos a seguir são retornados nas solicitações de pré-voo.
Este cabeçalho indica se a origem solicitada é permitida. Seu navegador escolherá ter sucesso/falha na solicitação, combinando a origem solicitada com esta.
Sintaxe:
Access-Control-Allow-Origin: *
Para solicitações sem credenciais, o valor *
pode ser especificado como curinga. Isso informa ao seu navegador para permitir solicitações de qualquer origem.
Access-Control-Allow-Origin: <origin>
Quando você recebe apenas uma origem no cabeçalho de resposta, significa que seu servidor/aplicativo web baseado na Origin
solicitada responde com a mesma Origin
, se permitido. Seu servidor também deve responder com Vary para indicar que varia com base no cabeçalho da solicitação.
Exemplo:
Access-Control-Allow-Origin: https://github.com
Seu navegador fará uma solicitação real se um dos valores neste cabeçalho corresponder. Quando o curinga *
é retornado, significa que qualquer método é permitido.
Sintaxe:
Access-Control-Allow-Methods: <method>, <method>, ...
Access-Control-Allow-Methods: *
Exemplo:
Access-Control-Allow-Methods: GET, POST
Seu navegador fará uma solicitação real se todos os cabeçalhos solicitados forem permitidos.
Sintaxe:
Access-Control-Allow-Headers: <header-name>, <header-name>
Access-Control-Allow-Headers: *
Exemplo:
Access-Control-Allow-Headers: Accept, Content-Type
Wildcard *
informa ao navegador que qualquer cabeçalho é permitido.
Informa por quanto tempo os resultados do pré-voo podem ser armazenados em cache.
Access-Control-Max-Age: <delta-seconds>
máximo não. de segundos, os resultados podem ser armazenados em cache.
Cada navegador tem limite máximo,
Varie o cabeçalho em geral usado para fins de armazenamento em cache para determinar se uma resposta armazenada em cache pode ser usada ou se deve ser armazenada novamente em cache com base no valor do cabeçalho.
No CORS, digamos que o servidor permita múltiplas origens com base no Origin
solicitado, ele retornará um URL específico em Access-Control-Allow-Origin
.
Sintaxe:
Vary: <header-name>
Exemplo:
Digamos que github.com permita que https://github.com e https://netflix.com solicitem recursos. Considere os seguintes cenários,
Cenário 1:
curl -X OPÇÕES https://github.com/api/v1/gists/1
Origin: https://github.com
Access-Control-Request-Method: GET
Access-Control-Request-Headers: Content-Type
Access-Control-Allow-Origin: https://github.com
Vary: Origin
Access-Control-Allow-Methods: GET, POST
Access-Control-Allow-Headers: Content-Type
Access-Control-Max-Age: 600
Agora, neste cenário, o navegador armazenará em cache os resultados da solicitação pré-voo por 10 minutos.
Cenário 2:
curl -X OPÇÕES https://github.com/api/v1/gists/1
Origin: https://netflix.com
Access-Control-Request-Method: GET
Access-Control-Request-Headers: Content-Type
Access-Control-Allow-Origin: https://netflix.com
Vary: Origin
Access-Control-Allow-Methods: GET, POST
Access-Control-Allow-Headers: Content-Type
Access-Control-Max-Age: 300
Agora você pode notar que Access-Control-Allow-Origin
contém https://netflix.com, este é um exemplo de como a resposta varia de acordo com determinado Origin
. O mesmo acontece com a idade máxima desta resposta, que é armazenada em cache por apenas 5 minutos, diferentemente do primeiro cenário.
Algumas solicitações não acionam solicitações pré-voo para CORS. Chamamos isso de solicitações simples . Deve atender às seguintes condições:
Um dos métodos permitidos:
Além dos cabeçalhos que são automaticamente criados pelo agente do usuário (por exemplo, Connection
ou User-Agent
), os únicos cabeçalhos que podem ser definidos manualmente são os cabeçalhos de solicitação na lista segura do CORS e os seguintes:
DPR
Downlink
Save-Data
Viewport-Width
Width
Nenhum ouvinte de evento é registrado em nenhum objeto XMLHttpRequestUpload
usado na solicitação.
Nenhum objeto ReadableStream
é usado na solicitação.
Exemplo:
Solicitar:
GET /api/v1/public-data/ HTTP/1.1
Host: bar.com
User-Agent: curl/7.69.1
Accept: */*
Origin: https://foo.com
Cabeçalhos de resposta:
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: application/xml
Quando uma solicitação retorna *
no cabeçalho Access-Control-Allow-Origin
. Isso significa que uma solicitação pode ser feita de qualquer Host
. Nesse caso, seu navegador não fará a solicitação pré-voo.
Seu navegador fará uma solicitação pré-voo para determinar se a solicitação real é segura para envio.
Exemplo:
const xhr = new XMLHttpRequest ( ) ;
xhr . open ( 'POST' , 'https://bar.com/api/v1/post-here/' ) ;
xhr . setRequestHeader ( 'X-PINGOTHER' , 'pingpong' ) ;
xhr . setRequestHeader ( 'Content-Type' , 'application/json;charset=UTF-8' ) ;
xhr . onreadystatechange = handler ;
xhr . send ( JSON . stringify ( { "email" : "[email protected]" } ) ) ;
Solicitação pré-voo:
OPTIONS /api/v1/post-here/
Host: bar.com
User-Agent: curl/7.69.1
Accept: */*
Origin: https://foo.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-PINGOTHER, Content-Type
HTTP/1.1 200 OK
Connection: Keep-Alive
Content-Type: application/json
Access-Control-Allow-Origin: https://foo.com
Access-Control-Allow-Methods: GET, POST
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type, Accept
Solicitação real:
POST -d '{foo: bar}' /api/v1/post-here/
Host: bar.com
User-Agent: curl/7.69.1
Accept: */*
Origin: https://foo.com
X-PINGOTHER: pingpong
Content-Type: application/json;charset=UTF-8
HTTP/1.1 200 OK
Connection: Keep-Alive
Content-Type: application/json
Access-Control-Allow-Origin: https://foo.com
Quando um cabeçalho não padrão como X-PINGOTHER
é definido, seu navegador não saberá se é seguro fazer a solicitação. Para garantir a segurança, seu navegador faz uma solicitação OPTIONS com Access-Control-Request-Headers
contendo X-PINGOTHER
e Content-Type
. Ao validar com cabeçalhos de resposta da solicitação pré-voo, seu navegador faz a solicitação real.
Em geral, quando você faz uma solicitação XHR, os cookies não são repassados junto com a solicitação. Quando houver necessidade de passar cookies, você terá que definir um sinalizador no objeto XMLHttpRequest
.
const xhr = new XMLHttpRequest ( ) ;
const url = 'http://bar.com/api/v1/credentialed-content/' ;
function callOtherDomain ( ) {
if ( invocation ) {
xhr . open ( 'GET' , url , true ) ;
xhr . withCredentials = true ;
xhr . onreadystatechange = handler ;
xhr . send ( ) ;
}
}
Solicitar:
POST -d '{foo: bar}' /api/v1/post-here/
Host: bar.com
User-Agent: curl/7.69.1
Accept: */*
Origin: https://foo.com
X-PINGOTHER: pingpong
Content-Type: application/json;charset=UTF-8
Cookie: _session=NyV14oKXiS6HHopaf9nT
Quando uma solicitação é feita XMLHttpRequest
e o sinalizador withCredentials
é definido, seu navegador transmitirá o Cookie
no cabeçalho da solicitação.
Resposta:
HTTP/1.1 200 OK
Connection: Keep-Alive
Content-Type: application/json
Access-Control-Allow-Origin: https://foo.com
Access-Control-Allow-Credentials: true
Cache-Control: no-cache
Pragma: no-cache
Set-Cookie: _session=AjBSqxj4T7bSySNTWeEm; expires=Wed, 31-05-2020 00:00:00 GMT
Quando seu navegador percebe Access-Control-Allow-Credentials
definido como verdadeiro. Ele respeitará o cabeçalho Set-Cookie
e definirá o cookie.
Importante: o curinga "*" não deve ser definido em Access-Control-Allow-Origin
como mencionado na seção Solicitações credenciadas e curingas.
Quando uma solicitação de credenciais é feita definindo o sinalizador withCredentials
, Access-Control-Expose-Headers
deve ser definido pelo servidor para permitir que o navegador saiba quais cabeçalhos podem ser acessados.
No mundo pré-cors, por padrão, os cabeçalhos de resposta não são acessíveis pelo navegador na solicitação CORS. Portanto, fica explícito para que o navegador procure esse cabeçalho para ler os cabeçalhos expostos. Dessa forma, a especificação CORS garante que navegadores antigos não quebrem.
Isso é retornado nas solicitações pré-voo. Quando seu navegador vir isso, ele poderá acessar o cabeçalho Set-Cookie
. Como mencionamos acima, em solicitações XHR normais, seu navegador não passará Cookie
no cabeçalho da solicitação, nem lerá o cabeçalho de resposta Set-Cookie
.
Sintaxe:
Access-Control-Allow-Credentials: true
Você pode encontrar um exemplo na seção Solicitação com credenciais.
Quando dizemos solicitação credenciada, significa cookies passados na solicitação XHR ou definidos por meio do cabeçalho de resposta Set-Cookie
. Quando uma solicitação XHR é feita com o sinalizador withCredentials, você espera receber uma resposta junto com os cookies a serem definidos. Porém, você não pode esperar Access-Control-Allow-Origin
seja "*" porque isso significaria que qualquer site pode usar esses cookies. Por esse motivo, seu navegador falharia na solicitação se visse "*" no cabeçalho de resposta Access-Control-Allow-Origin
.
Quando uma solicitação pré-voo responde com 301/302, alguns navegadores podem não suportar isso atualmente. Você pode receber erros como,
The request was redirected to 'https://example.com/foo', which is disallowed for cross-origin requests that require preflight
Request requires preflight, which is disallowed to follow cross-origin redirect
Nota: Para soluções alternativas, verifique Solicitações pré-voadas e documentos de redirecionamento da Mozilla.
O navegador possui configurações para rejeitar todos os cookies third-party
, quando um usuário permite isso. Por exemplo, se uma solicitação for feita de https://foo.com
e o servidor estiver em https://bar.com
, seu navegador não definirá cookies enviados por https://bar.com
.