como ignorar o Access-Control-Allow-Origin?

197

Estou fazendo uma chamada ajax para meu próprio servidor em uma plataforma que eles definem para impedir essas chamadas ajax (mas preciso que ele busque os dados do meu servidor para exibir os dados recuperados do banco de dados do meu servidor). Meu script ajax está funcionando, ele pode enviar os dados para o script php do meu servidor para permitir o processamento. No entanto, ele não pode recuperar os dados processados, pois são bloqueados pelo"Access-Control-Allow-Origin"

Não tenho acesso à fonte / núcleo dessa plataforma. então não consigo remover o script que não me permite fazer isso. (A P / SI usou o Console do Google Chrome e descobriu este erro)

O código Ajax, como mostrado abaixo:

 $.ajax({
     type: "GET",
     url: "http://example.com/retrieve.php",
     data: "id=" + id + "&url=" + url,
     dataType: 'json',   
     cache: false,
     success: function(data)
      {
        var friend = data[1];              
        var blog = data[2];           
        $('#user').html("<b>Friends: </b>"+friend+"<b><br> Blogs: </b>"+blog);

      } 
  });

ou existe um JSONcódigo equivalente ao script ajax acima? Eu acho que JSONé permitido.

Espero que alguém possa me ajudar.

ETAN
fonte
todas as respostas para sua pergunta até agora explicaram uma maneira de reescrever o código do servidor para que o ajax funcione. Nenhum deles é sobre contornar, como você perguntou especificamente em sua pergunta. Você encontrou alguma maneira de ignorar esse cabeçalho? Eu realmente duvido que haveria um.
Moradnejad
não há como contornar isso. mas você pode colocar um arquivo no seu back-end que executa a solicitação. Então você chama por ajax o arquivo em seu próprio servidor, esse arquivo carrega os dados de retrieve.php e os envia de volta ao seu javascript. Nesse caso, não há regras do CORS bloqueando você.
Jona Paulus

Respostas:

367

Coloque isso em cima de retrieve.php:

header('Access-Control-Allow-Origin: *');  

Observe que isso desativa efetivamente a proteção CORS e deixa seus usuários expostos a ataques. Se você não tiver certeza absoluta de que precisa permitir todas as origens, troque isso para uma origem mais específica:

header('Access-Control-Allow-Origin: https://www.example.com')

Consulte a resposta da pilha a seguir para entender melhor Access-Control-Allow-Origin

https://stackoverflow.com/a/10636765/413670

Rafay
fonte
54
Isso é bastante inseguro. Confira minha resposta na parte inferior.
Rob
3
tnx, mas você não deve permitir o acesso a todas as origens, como mencionado por @RobQuist em seu comentário, e em sua resposta dada uma melhor abordagem
Rafay
2
Encontrei esta página porque precisava "ignorar" o controle de acesso em um servidor. A solução aqui não está ignorando nada, mas simplesmente configurando corretamente o Controle de Acesso em seu próprio servidor. Caso alguém lá fora realmente precise ignorar isso, pode usar o file_get_contents do PHP ($ remote_url) ;. Obviamente, existem muitas maneiras de fazer isso, mas foi assim que eu fiz.
Shawn Whinnery
1
@ ShawnWhinnery que é basicamente o ato de "proxy". Boa solução se você realmente deseja carregar dinamicamente dados de outro site que você não tem controle.
28416 Rob
1
queria executar o script PHP a partir do dotnet core - movi o script php para minha outra URL, mas estava recebendo erro de script entre sites. adicionou o código que você mostrou ao topo do PHP e funcionou perfeitamente. Obrigado!
Raddevus 21/04/19
291

Ok, mas todos sabem que o * é um curinga e permite scripts entre sites de todos os domínios?

Você gostaria de enviar vários Access-Control-Allow-Origincabeçalhos para todos os sites autorizados - mas infelizmente não é oficialmente suportado o envio de váriosAccess-Control-Allow-Origin cabeçalhos ou a inserção de várias origens.

Você pode resolver isso verificando a origem e enviando de volta aquela no cabeçalho, se for permitido:

$origin = $_SERVER['HTTP_ORIGIN'];
$allowed_domains = [
    'http://mysite1.com',
    'https://www.mysite2.com',
    'http://www.mysite2.com',
];

if (in_array($origin, $allowed_domains)) {
    header('Access-Control-Allow-Origin: ' . $origin);
}

Isso é muito mais seguro. Você pode editar a correspondência e alterá-la para uma função manual com alguma expressão regular ou algo parecido. Pelo menos isso enviará de volta apenas 1 cabeçalho e você terá certeza de que é o local de origem da solicitação. Observe que todos os cabeçalhos HTTP podem ser falsificados, mas esse cabeçalho é para a proteção do cliente. Não proteja seus próprios dados com esses valores. Se você quiser saber mais, leia um pouco sobre CORS e CSRF.

Por que é mais seguro?

Permitindo acesso a partir de outros locais, seu site confiável permite o aumento do número de sessões. Vou dar um pequeno exemplo - a imagem do Facebook permite uma origem curinga - isso significa que você pode criar seu próprio site em algum lugar e acionar chamadas AJAX (ou abrir iframes) para o facebook. Isso significa que você pode pegar as informações de login do facebook de um visitante do seu site. Pior ainda - você pode escreverPOST criar solicitações de e publicar dados no facebook de alguém - apenas enquanto eles navegam no seu site.

Seja muito cauteloso ao usar os ACAOcabeçalhos!

Roubar
fonte
12
Eu acho que você precisa colocar http: // na frente de cada item da lista. Pelo menos eu fiz para um site em que estava trabalhando.
blak3r
2
Infelizmente, isso não parece funcionar. Acredito que apenas uma exceção pode ser fornecida por chamada ao cabeçalho ().
lewsid
5
@ Shanimal & lewsid -> Eu acho que vírgula separada não funciona de fato. Referência: w3.org/TR/cors
Rob
3
Para lidar com uma lista de domínios, aqui uma resposta relevante: stackoverflow.com/a/1850482/766177
Valentin Despa
13
Não faz sentido adicionar 4 cabeçalhos como esse, pois cada chamada header()substitui o cabeçalho anterior do mesmo tipo. Então, na verdade, tudo o que você está fazendo é definir o último cabeçalho. A entrada manual afirma que você pode definir um segundo parâmetro falsepara impedir que o cabeçalho anterior seja substituído.
21716 BadHorsie
31

Aviso , o Chrome (e outros navegadores) reclamarão que vários cabeçalhos da ACAO estão definidos se você seguir algumas das outras respostas.

O erro será algo como XMLHttpRequest cannot load ____. The 'Access-Control-Allow-Origin' header contains multiple values '____, ____, ____', but only one is allowed. Origin '____' is therefore not allowed access.

Tente o seguinte:

$http_origin = $_SERVER['HTTP_ORIGIN'];

$allowed_domains = array(
  'http://domain1.com',
  'http://domain2.com',
);

if (in_array($http_origin, $allowed_domains))
{  
    header("Access-Control-Allow-Origin: $http_origin");
}

fonte
6
Essa é uma solução ainda melhor que a que eu publiquei.
Rob
7

Corrigi esse problema ao chamar um Controlador MVC3. Eu adicionei:

Response.AddHeader("Access-Control-Allow-Origin", "*"); 

antes do meu

return Json(model, JsonRequestBehavior.AllowGet);

E também $.ajaxestava reclamando que ele não aceita o cabeçalho do tipo Content na minha chamada ajax, então comentei porque sei que seu JSON estava sendo passado para a ação.

Espero que ajude.

Atif Rehman
fonte
2

É uma péssima ideia usar *, o que deixa você aberto a scripts entre sites. Você basicamente quer seu próprio domínio o tempo todo, com escopo definido nas configurações SSL atuais e, opcionalmente, em domínios adicionais. Você também deseja que todos sejam enviados como um cabeçalho. O seguinte sempre autorizará seu próprio domínio no mesmo escopo SSL da página atual e, opcionalmente, também poderá incluir qualquer número de domínios adicionais. Ele os enviará todos como um cabeçalho e substituirá o (s) anterior (es), se outra coisa já os tiver enviado para evitar qualquer chance do navegador reclamar sobre o envio de vários cabeçalhos de controle de acesso.

class CorsAccessControl
{
    private $allowed = array();

    /**
     * Always adds your own domain with the current ssl settings.
     */
    public function __construct()
    {
        // Add your own domain, with respect to the current SSL settings.
        $this->allowed[] = 'http'
            . ( ( array_key_exists( 'HTTPS', $_SERVER )
                && $_SERVER['HTTPS'] 
                && strtolower( $_SERVER['HTTPS'] ) !== 'off' ) 
                    ? 's' 
                    : null )
            . '://' . $_SERVER['HTTP_HOST'];
    }

    /**
     * Optionally add additional domains. Each is only added one time.
     */
    public function add($domain)
    {
        if ( !in_array( $domain, $this->allowed )
        {
            $this->allowed[] = $domain;
        }
    /**
     * Send 'em all as one header so no browsers grumble about it.
     */
    public function send()
    {
        $domains = implode( ', ', $this->allowed );
        header( 'Access-Control-Allow-Origin: ' . $domains, true ); // We want to send them all as one shot, so replace should be true here.
    }
}

Uso:

$cors = new CorsAccessControl();

// If you are only authorizing your own domain:
$cors->send();

// If you are authorizing multiple domains:
foreach ($domains as $domain)
{
    $cors->add($domain);
}
$cors->send();

Você entendeu a ideia.

mopsyd
fonte
1

Você já tentou adicionar o cabeçalho Access-Control-Allow-Origin à resposta enviada do seu servidor? Como Access-Control-Allow-Origin: *?

Daniel Brockman
fonte
1
É um cabeçalho HTTP que o servidor envia para informar ao navegador que não há problema em revelar o resultado ao script de chamada, apesar do domínio de origem do script não corresponder ao domínio do servidor. Leia sobre compartilhamento de recursos de origem cruzada !
Daniel Brockman