XMLHttpRequest não pode carregar XXX Nenhum cabeçalho 'Access-Control-Allow-Origin'

111

tl; dr; Sobre a mesma política de origem

Eu tenho um processo Grunt que inicia uma instância do servidor express.js. Isso estava funcionando perfeitamente bem até agora, quando começou a exibir uma página em branco com o seguinte aparecendo no log de erros no console do desenvolvedor no Chrome (versão mais recente):

XMLHttpRequest não pode carregar https://www.example.com/ Nenhum cabeçalho 'Access-Control-Allow-Origin' está presente no recurso solicitado. Portanto, o acesso de origem ' http: // localhost: 4300 ' não é permitido.

O que está me impedindo de acessar a página?

Peter David Carter
fonte
Estou trabalhando no site e estava bom cinco minutos atrás.
Peter David Carter
1
ele emite cabeçalhos CORS? talvez se você compartilhasse algum código, seria mais fácil ver
Jaromanda X
Plausivelmente. Qual departamento devo pedir para descobrir? Eu só faço o backbone.marionette, principalmente ...
Peter David Carter
Sim. Suponho que as organizações dos departamentos nem sempre são uniformes, então é possivelmente uma pergunta nebulosa, mas eu gostaria de saber um pouco sobre o backend / roteamento / sys-admin da minha empresa e isso parecia uma boa desculpa para me familiarizar eu mesmo, então, se houver problemas no futuro, posso ajudar.
Peter David Carter
Gostaria de perguntar a alguém do lado do servidor dentro de sua operação. Eles devem ter mudado isso em você se você era capaz de acessá-lo antes.
Larry Lane

Respostas:

204

tl; dr - Há um resumo no final e títulos na resposta para facilitar a localização das partes relevantes. Porém, é recomendável ler tudo, pois fornece um pano de fundo útil para entender o porquê que torna ver como o como mais fácil se aplica em diferentes circunstâncias.

Sobre a mesma política de origem

Esta é a política da mesma origem . É um recurso de segurança implementado por navegadores.

Seu caso específico está mostrando como ele é implementado para XMLHttpRequest (e você obterá resultados idênticos se usar fetch), mas também se aplica a outras coisas (como imagens carregadas em um <canvas>ou documentos carregados em um<iframe> ), apenas com implementações ligeiramente diferentes.

(Estranhamente, também se aplica a fontes CSS, mas isso ocorre porque foundries insistiu em DRM e não para os problemas de segurança que a política da mesma origem geralmente cobre).

O cenário padrão que demonstra a necessidade do SOP pode ser demonstrado com três personagens :

  • Alice é uma pessoa com um navegador da web
  • Bob administra um site ( https://www.[website].com/em seu exemplo)
  • Mallory administra um site ( http://localhost:4300no seu exemplo)

Alice está logada no site de Bob e possui alguns dados confidenciais lá. Talvez seja uma intranet da empresa (acessível apenas para navegadores na LAN), ou seu banco online (acessível apenas com um cookie que você obtém após inserir um nome de usuário e uma senha).

Alice visita o site de Mallory que tem algum JavaScript que faz com que o navegador de Alice faça uma solicitação HTTP para o site de Bob (de seu endereço IP com seus cookies, etc). Isso pode ser tão simples quanto usar XMLHttpRequeste ler oresponseText .

A política de mesma origem do navegador impede que o JavaScript leia os dados retornados pelo site de Bob (que Bob e Alice não querem que Mallory acesse). (Observe que você pode, por exemplo, exibir uma imagem usando um <img>elemento entre as origens, porque o conteúdo da imagem não é exposto a JavaScript (ou Mallory) ... a menos que você jogue a tela na mistura, caso em que irá gerar uma mesma origem erro de violação).


Por que a Política da Mesma Origem se aplica quando você acha que não deveria

Para qualquer URL, é possível que o SOP não seja necessário. Alguns cenários comuns em que esse é o caso são:

  • Alice, Bob e Mallory são a mesma pessoa.
  • Bob está fornecendo informações totalmente públicas

… Mas o navegador não tem como saber se alguma das opções acima é verdadeira, portanto, a confiança não é automática e o SOP é aplicado. A permissão deve ser concedida explicitamente antes que o navegador forneça os dados fornecidos a um site diferente.


Por que a Política de Mesma Origem se aplica apenas a JavaScript em uma página da web

Extensões do navegador *, a guia Rede nas ferramentas de desenvolvedor do navegador e aplicativos como o Postman são softwares instalados. Eles não estão passando dados de um site para o JavaScript pertencente a um site diferente apenas porque você visitou esse site diferente . Instalar software geralmente requer uma escolha mais consciente.

Não existe um terceiro (Mallory) considerado um risco.

*As extensões do navegador precisam ser escritas com cuidado para evitar problemas de origem cruzada. Consulte a documentação do Chrome, por exemplo .


Por que você pode exibir dados na página sem lê-los com JS

Existem várias circunstâncias em que o site de Mallory pode fazer com que um navegador busque dados de terceiros e os exiba (por exemplo, adicionando um <img>elemento para exibir uma imagem). Não é possível para o JavaScript de Mallory ler os dados nesse recurso, apenas o navegador de Alice e o servidor de Bob podem fazer isso, portanto, ainda é seguro.


CORS

O cabeçalho de respostaAccess-Control-Allow-Origin HTTP referido na mensagem de erro é parte do padrão CORS que permite a Bob conceder permissão explicitamente ao site de Mallory para acessar os dados por meio do navegador de Alice.

Uma implementação básica incluiria apenas:

Access-Control-Allow-Origin: *

… Nos cabeçalhos de resposta para permitir que qualquer site leia os dados.

Access-Control-Allow-Origin: http://example.com/

… Permitiria que apenas um site específico o acessasse, e Bob pode gerar isso dinamicamente com base no cabeçalho da Origin solicitação para permitir que vários sites, mas não todos, o acessem.

Os detalhes de como Bob define esse cabeçalho de resposta dependem do servidor HTTP de Bob e / ou da linguagem de programação do lado do servidor. Há uma coleção de guias para várias configurações comuns que podem ajudar.

Modelo de onde as regras CORS são aplicadas

NB: Algumas solicitações são complexas e enviam uma solicitação OPTIONS de preflight que o servidor terá que responder antes que o navegador envie a solicitação GET / POST / PUT / Whatever que o JS deseja fazer. Implementações de CORS que apenas adicionam Access-Control-Allow-OriginURLs específicos geralmente são enganadas por isso.


Obviamente, conceder permissão via CORS é algo que Bob só faria se:

  • Os dados não eram privados ou
  • Mallory era confiável

Mas eu não sou Bob!

Não existe um mecanismo padrão para Mallory adicionar esse cabeçalho porque ele precisa vir do site de Bob, que ela não controla.

Se Bob estiver executando uma API pública, pode haver um mecanismo para ativar o CORS (talvez formatando a solicitação de uma determinada maneira ou uma opção de configuração após fazer login em um site do Portal do Desenvolvedor para o site de Bob). No entanto, isso terá que ser um mecanismo implementado por Bob. Mallory pode ler a documentação no site de Bob para ver se algo está disponível, ou ela pode falar com Bob e pedir-lhe para implementar o CORS.


Mensagens de erro que mencionam "Resposta para comprovação"

Algumas solicitações de origem cruzada são pré-iluminadas .

Isso acontece quando (falando grosso modo) você tenta fazer uma solicitação de origem cruzada que:

  • Inclui credenciais como cookies
  • Não pode ser gerado com um formulário HTML regular (por exemplo, tem cabeçalhos personalizados ou um Content-Type que você não pode usar em um formulário enctype).

Se você está fazendo algo que precisa de uma simulação

Nestes casos, o resto desta resposta ainda se aplica, mas você também precisa se certificar de que o servidor pode ouvir a solicitação de comprovação (que será OPTIONS(e não GET, POSTou o que quer que você esteja tentando enviar) e responder a ela com a Access-Control-Allow-Origincabeçalho, mas também Access-Control-Allow-Methodse Access-Control-Allow-Headerspara permitir seus métodos HTTP ou cabeçalhos específicos.

Se você estiver disparando uma simulação por engano

Às vezes, as pessoas cometem erros ao tentar construir solicitações Ajax e, às vezes, isso aciona a necessidade de uma comprovação. Se a API for projetada para permitir solicitações de origem cruzada, mas não exigir nada que precise de uma comprovação, isso pode interromper o acesso.

Erros comuns que acionam isso incluem:

  • tentando colocar Access-Control-Allow-Origine outros cabeçalhos de resposta CORS na solicitação. Eles não pertencem à solicitação, não fazem nada de útil (qual seria o ponto de um sistema de permissões em que você poderia conceder permissão a si mesmo?) E devem aparecer apenas na resposta.
  • tentando colocar um Content-Type: application/jsoncabeçalho em uma solicitação GET que não possui corpo de solicitação para descrever o conteúdo (normalmente quando o autor confunde Content-Typee Accept).

Em qualquer um desses casos, remover o cabeçalho de solicitação extra geralmente será suficiente para evitar a necessidade de um preflight (o que resolverá o problema ao se comunicar com APIs que suportam solicitações simples, mas não solicitações preflight).


Respostas opacas

Às vezes, você precisa fazer uma solicitação HTTP, mas não precisa ler a resposta. por exemplo, se você estiver postando uma mensagem de log no servidor para gravação.

Se você estiver usando a fetchAPI (em vez de XMLHttpRequest), poderá configurá-la para não tentar usar o CORS.

Observe que isso não permitirá que você faça nada que exija que o CORS faça. Você não conseguirá ler a resposta. Você não poderá fazer uma solicitação que exija um preflight.

Isso permitirá que você faça uma solicitação simples, não veja a resposta e não preencha o console do desenvolvedor com mensagens de erro.

Como fazer isso é explicado pela mensagem de erro do Chrome fornecida quando você faz uma solicitação usando fetche não obtém permissão para visualizar a resposta com CORS:

O acesso para buscar em ' https://example.com/' da origem ' https://example.net' foi bloqueado pela política CORS: Nenhum Access-Control-Allow-Origincabeçalho ' ' está presente no recurso solicitado. Se uma resposta opaca atender às suas necessidades, defina o modo da solicitação como 'no-cors' para buscar o recurso com o CORS desativado.

Portanto:

fetch("http://example.com", { mode: "no-cors" });

Alternativas ao CORS

JSONP

Bob também poderia fornecer os dados usando um hack como JSONP, que é como as pessoas faziam Ajax de origem cruzada antes do CORS aparecer.

Ele funciona apresentando os dados na forma de um programa JavaScript que injeta os dados na página de Mallory.

Requer que Mallory confie em Bob para não fornecer código malicioso.

Observe o tema comum: o site que fornece os dados deve informar ao navegador que não há problema em um site de terceiros acessar os dados que está enviando ao navegador.

Como o JSONP funciona anexando um <script>elemento para carregar os dados na forma de um programa JavaScript que chama uma função já na página, a tentativa de usar a técnica JSONP em um URL que retorna JSON falhará - normalmente com um erro CORB - porque JSON não é JavaScript.

Mova os dois recursos para uma única Origem

Se o documento HTML em que o JS é executado e a URL solicitada estiverem na mesma origem (compartilhando o mesmo esquema, nome de host e porta), a política de mesma origem concede permissão por padrão. CORS não é necessário.

Um proxy

Mallory poderia usar código do lado do servidor para buscar os dados (que ela poderia então passar de seu servidor para o navegador de Alice através de HTTP como de costume).

Será:

  • adicionar cabeçalhos CORS
  • converter a resposta para JSONP
  • existem na mesma origem do documento HTML

Esse código do lado do servidor pode ser escrito e hospedado por terceiros (como CORS Anywhere). Observe as implicações de privacidade disso: O terceiro pode monitorar quem faz proxy do quê em seus servidores.

Bob não precisaria conceder nenhuma permissão para que isso acontecesse.

Não há implicações de segurança aqui, pois isso é apenas entre Mallory e Bob. Não há como Bob pensar que Mallory é Alice e fornecer a Mallory dados que devem ser mantidos em sigilo entre Alice e Bob.

Conseqüentemente, Mallory só pode usar essa técnica para ler dados públicos .

Observe, no entanto, que pegar conteúdo do site de outra pessoa e exibi-lo por conta própria pode ser uma violação de direitos autorais e abrir você para uma ação legal.

Escrever algo diferente de um aplicativo da web

Conforme observado na seção "Por que a Política de Mesma Origem se aplica apenas ao JavaScript em uma página da web", você pode evitar o SOP não escrevendo JavaScript em uma página da web.

Isso não significa que você não pode continuar usando JavaScript e HTML, mas pode distribuí-los usando algum outro mecanismo, como Node-WebKit ou PhoneGap.

Extensões de navegador

É possível que uma extensão do navegador injete os cabeçalhos CORS na resposta antes que a política da mesma origem seja aplicada.

Eles podem ser úteis para o desenvolvimento, mas não são práticos para um site de produção (pedir a cada usuário do seu site para instalar uma extensão do navegador que desabilite um recurso de segurança do navegador não é razoável).

Eles também tendem a funcionar apenas com solicitações simples (falha ao lidar com solicitações OPTIONS de comprovação).

Ter um ambiente de desenvolvimento adequado com um servidor de desenvolvimento local geralmente é a melhor abordagem.


Outros riscos de segurança

Observe que SOP / CORS não atenua ataques XSS , CSRF ou SQL Injection que precisam ser tratados de forma independente.


Resumo

  • Não há nada que você possa fazer em seu código do lado do cliente que permitirá o acesso do CORS ao servidor de outra pessoa .
  • Se você controlar o servidor, a solicitação está sendo feita para: Adicionar permissões CORS a ele.
  • Se você for amigável com a pessoa que o controla: Faça com que eles adicionem permissões CORS a ele.
  • Se for um serviço público:
    • Leia a documentação da API para ver o que dizem sobre como acessá-la com JavaScript do lado do cliente:
      • Eles podem dizer para você usar URLs específicos
      • Eles podem suportar JSONP
      • Eles podem não suportar o acesso de origem cruzada a partir do código do lado do cliente (isso pode ser uma decisão deliberada por motivos de segurança, especialmente se você tiver que passar uma chave de API personalizada em cada solicitação).
    • Certifique-se de não disparar uma solicitação de comprovação desnecessária. A API pode conceder permissão para solicitações simples, mas não para solicitações preflight.
  • Se nenhuma das opções acima se aplicar: Faça com que o navegador converse com o seu servidor e, em seguida, faça com que o seu servidor busque os dados do outro servidor e os transmita. (Existem também serviços hospedados de terceiros que anexam cabeçalhos CORS a recursos publicamente acessíveis que você pode usar).
Quentin
fonte
Se eu executar uma LAN local em um servidor web e tentar carregar ajax a partir do IP / URL, funcionará? Eu não tentei isso ainda. como meu servidor da web retendo dados json seria um MCU
Ciasto piekarz
@Ciastopiekarz - Regras normais de mesma origem / origem diferente se aplicam. Regras normais de roteamento de rede se aplicam.
Quentin
25
A resposta mais completa que já li, em vez de apenas um link sobre cors ..
pungggi
@Quentin - Uau! +1! Então, o que devo entender é que se Alice usa a extensão CORS, o servidor pensa que suas chamadas http não são de javascript, mas de uma extensão de navegador, e trata isso como uma solicitação normal de mesma origem?
snippetkid
@snippetkid - Não. No caso usual, o servidor enviará cabeçalhos CORS em cada resposta e não se importando de onde a solicitação veio. É responsabilidade do navegador permitir ou negar acesso aos dados do JS com base nos cabeçalhos CORS na resposta. (As coisas ficam um pouco / mais complexas no servidor quando se trata de solicitações de comprovação)
Quentin
3

O servidor de destino deve permitir a solicitação de origem cruzada. Para permitir a passagem expressa, basta lidar com a solicitação de opções de http:

app.options('/url...', function(req, res, next){
   res.header('Access-Control-Allow-Origin', "*");
   res.header('Access-Control-Allow-Methods', 'POST');
   res.header("Access-Control-Allow-Headers", "accept, content-type");
   res.header("Access-Control-Max-Age", "1728000");
   return res.sendStatus(200);
});
Daphoque
fonte
3

Como isso não é mencionado na resposta aceita.

  • Este não é o caso para esta pergunta exata, mas pode ajudar outras pessoas que procuram esse problema
  • Isso é algo que você pode fazer em seu código-cliente para evitar erros de CORS em alguns casos .

Você pode fazer uso de solicitações simples .
Para realizar uma 'Solicitação Simples', a solicitação deve atender a várias condições. Por exemplo, permitindo apenas POST, GETe HEADmétodo, bem como permitindo apenas alguns dada cabeçalhos (você pode encontrar todas as condições aqui ).

Se o código do cliente não definir explicitamente os cabeçalhos afetados (por exemplo, "Aceitar") com um valor fixo na solicitação, pode ocorrer que alguns clientes definam esses cabeçalhos automaticamente com alguns valores "não padrão", fazendo com que o servidor não os aceite como Solicitação simples - que apresentará um erro CORS.

zwif
fonte
2

Isso está acontecendo por causa do erro CORS. CORS significa Cross Origin Resource Sharing. Em palavras simples, esse erro ocorre quando tentamos acessar um domínio / recurso de outro domínio.

Leia mais sobre isso aqui: Erro CORS com jquery

Para corrigir isso, se você tiver acesso ao outro domínio, você terá que permitir Access-Control-Allow-Origin no servidor. Isso pode ser adicionado nos cabeçalhos. Você pode habilitar isso para todos os pedidos / domínios ou um domínio específico.

Como fazer uma pós-solicitação de compartilhamento de recursos de origem cruzada (CORS) funcionar

Esses links podem ajudar

Vishnu
fonte
0

Este problema CORS não foi mais elaborado (por outras causas).

Estou tendo esse problema atualmente por outro motivo. Meu front end também está retornando o erro de cabeçalho 'Access-Control-Allow-Origin'.

Só que apontei o URL errado, então esse cabeçalho não foi refletido corretamente (no qual eu sempre presumo que sim). localhost (front end) -> chamada para http não seguro (supostamente https), certifique-se de que o endpoint da API do front end está apontando para o protocolo correto.

morph85
fonte
0

Recebi o mesmo erro no console do Chrome.

Meu problema era que eu estava tentando acessar o site usando em http://vez de https://. Então não tinha nada para consertar, só tinha que ir para o mesmo site usando https.

Subhashi
fonte
-1

Solicitação "Get" com transformação de cabeçalhos anexada à solicitação "Opções". Então ocorrem problemas de política de Cors. Você deve implementar a solicitação de "Opções" em seu servidor.

kira
fonte
-6

Você deve habilitar o CORS para fazê-lo funcionar.

Perostek Balveda
fonte