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:4300
no 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 XMLHttpRequest
e 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.
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-Origin
URLs 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
, POST
ou o que quer que você esteja tentando enviar) e responder a ela com a Access-Control-Allow-Origin
cabeçalho, mas também Access-Control-Allow-Methods
e Access-Control-Allow-Headers
para 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-Origin
e 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/json
cabeç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-Type
e 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 fetch
API (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 fetch
e 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-Origin
cabeç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).