Maneiras de contornar a política de mesma origem

150

A mesma política de origem

Eu queria criar um wiki da comunidade sobre políticas de mesma origem HTML / JS para ajudar a quem procura esse tópico. Este é um dos tópicos mais pesquisados ​​sobre SO e não existe um wiki consolidado, então aqui vou eu :)

A mesma política de origem impede que um documento ou script carregado de uma origem obtenha ou defina propriedades de um documento de outra origem. Essa política remonta ao Netscape Navigator 2.0.

Quais são algumas das suas formas favoritas de adotar políticas de mesma origem?

Por favor, mantenha exemplos detalhados e, de preferência, também vincule suas fontes.

David Titarenco
fonte
4
boa idéia .. Você deve colocar seus exemplos em respostas; tal como está, eles fazem a pergunta bastante volumoso
Shog9
1
Você também deve adicionar uma lista de implicações de segurança para cada abordagem. JSONP é altamente inseguro para dados particulares.
Erlend
Por que o fim? Esta questão (wiki) tem sido bastante útil nos últimos 2 anos. Além disso, muitas respostas são suportadas por referências. Uma explicação seria apreciada, pois uma not constructivetag parece totalmente insana. Votou para reabrir.
David Titarenco 15/08/12

Respostas:

84

O document.domainmétodo

  • Tipo de método: iframe .

Observe que este é um método iframe que define o valor de document.domain como um sufixo do domínio atual. Se fizer isso, o domínio mais curto será usado para verificações de origem subsequentes. Por exemplo, suponha que um script no documento em http://store.company.com/dir/other.htmlexecute a seguinte instrução:

document.domain = "company.com";

Após a execução dessa instrução, a página passaria na verificação de origem com http://company.com/dir/page.html. No entanto, pelo mesmo raciocínio, company.com não poderia definir document.domain a othercompany.com.

Com esse método, você poderá executar o javascript de um iframe originado em um subdomínio em uma página originada no domínio principal. Este método não é adequado para recursos entre domínios, pois navegadores como o Firefox não permitem alterar o domínio document.domainpara um domínio completamente estranho.

Fonte: https://developer.mozilla.org/en/Same_origin_policy_for_JavaScript

O método de compartilhamento de recursos de origem cruzada

  • Tipo de método: AJAX .

O compartilhamento de recursos de origem cruzada (CORS) é um rascunho de trabalho do W3C que define como o navegador e o servidor devem se comunicar ao acessar fontes de origens. A idéia básica por trás do CORS é usar cabeçalhos HTTP personalizados para permitir que o navegador e o servidor saibam o suficiente um sobre o outro para determinar se a solicitação ou resposta deve ter êxito ou falhar.

Para uma solicitação simples, que usa um GETou POSTsem cabeçalhos personalizados e cujo corpo é text/plain, a solicitação é enviada com um cabeçalho extra chamado Origin. O cabeçalho Origin contém a origem (protocolo, nome de domínio e porta) da página solicitante, para que o servidor possa determinar facilmente se deve ou não servir uma resposta. Um Origincabeçalho de exemplo pode ser assim:

Origin: http://www.stackoverflow.com

Se o servidor decidir que a solicitação deve ser permitida, ele envia um Access-Control-Allow-Origincabeçalho ecoando a mesma origem que foi enviada ou *se é um recurso público. Por exemplo:

Access-Control-Allow-Origin: http://www.stackoverflow.com

Se esse cabeçalho estiver ausente ou as origens não corresponderem, o navegador não permitirá a solicitação. Se tudo estiver bem, o navegador processará a solicitação. Observe que nem as solicitações nem as respostas incluem informações sobre cookies.

A equipe da Mozilla sugere em seu post sobre o CORS que você deve verificar a existência da withCredentials propriedade para determinar se o navegador suporta o CORS via XHR. Você pode associar a existência do XDomainRequestobjeto a todos os navegadores:

function createCORSRequest(method, url){
    var xhr = new XMLHttpRequest();
    if ("withCredentials" in xhr){
        xhr.open(method, url, true);
    } else if (typeof XDomainRequest != "undefined"){
        xhr = new XDomainRequest();
        xhr.open(method, url);
    } else {
        xhr = null;
    }
    return xhr;
}

var request = createCORSRequest("get", "http://www.stackoverflow.com/");
if (request){
    request.onload = function() {
        // ...
    };
    request.onreadystatechange = handler;
    request.send();
}

Observe que, para que o método CORS funcione, você precisa ter acesso a qualquer tipo de mecânico de cabeçalho do servidor e não pode simplesmente acessar qualquer recurso de terceiros.

Fonte: http://www.nczonline.net/blog/2010/05/25/cross-domain-ajax-with-cross-origin-resource-sharing/

O window.postMessagemétodo

  • Tipo de método: iframe .

window.postMessage, quando chamado, faz com que um MessageEventseja despachado na janela de destino quando qualquer script pendente que deve ser executado for concluído (por exemplo, os manipuladores de eventos restantes, se window.postMessagefor chamado de um manipulador de eventos, tempos limite pendentes definidos anteriormente, etc.). A MessageEventtem o tipo de mensagem, uma datapropriedade que está definido para o valor da cadeia do primeiro argumento fornecido para window.postMessage, uma originpropriedade que corresponde à origem do documento principal na janela chamando window.postMessageno momento window.postMessagefoi chamado, e uma sourcepropriedade que é a janela de qual window.postMessageé chamado.

Para usar window.postMessage, um ouvinte de evento deve ser anexado:

    // Internet Explorer
    window.attachEvent('onmessage',receiveMessage);

    // Opera/Mozilla/Webkit
    window.addEventListener("message", receiveMessage, false);

E uma receiveMessagefunção deve ser declarada:

function receiveMessage(event)
{
    // do something with event.data;
}

O iframe externo também deve enviar eventos corretamente via postMessage:

<script>window.parent.postMessage('foo','*')</script>

Qualquer janela pode acessar esse método em qualquer outra janela, a qualquer momento, independentemente do local do documento na janela, para enviar uma mensagem. Conseqüentemente, qualquer ouvinte de evento usado para receber mensagens deve primeiro verificar a identidade do remetente da mensagem, usando a origem e possivelmente as propriedades de origem. Isso não pode ser subestimado: a falha em verificar as propriedades origine possivelmente sourceativa os ataques de script entre sites.

Fonte: https://developer.mozilla.org/en/DOM/window.postMessage

David Titarenco
fonte
Espero que não seja tarde demais para obter uma resposta: a única pergunta é: localhost SEMPRE é uma exceção? isso sempre não é permitido? devo parar de testar através do meu host local?
precisa
1
Não sei por que, mas quando defino: em Access-Control-Allow-Origin: http://www.stackoverflow.com/vez de: Access-Control-Allow-Origin: http://www.stackoverflow.com(barra no final do URL), ele não funciona no Safari e no FF, mas funciona no Chrome. Obviamente, sem barra funciona bem em todos os navegadores.
Mtfk
1
Pode valer a pena informar às pessoas que o postMessagemétodo funciona apenas para navegadores que o suportam, pois é uma adição ao HTML5. Este plugin tenta explicar isso. Apenas mencionando, porque estou aprendendo isso da maneira mais difícil.
IronicMuffin
41

O método de proxy reverso

  • Tipo de método: Ajax

A configuração de um proxy reverso simples no servidor permitirá que o navegador use caminhos relativos para as solicitações do Ajax, enquanto o servidor atuaria como proxy para qualquer local remoto.

Se estiver usando mod_proxy no Apache, a diretiva de configuração fundamental para configurar um proxy reverso é a ProxyPass. É normalmente usado da seguinte maneira:

ProxyPass     /ajax/     http://other-domain.com/ajax/

Nesse caso, o navegador poderia solicitar /ajax/web_service.xmlcomo um URL relativo, mas o servidor serviria como um proxy para http://other-domain.com/ajax/web_service.xml.

Uma característica interessante desse método é que o proxy reverso pode distribuir facilmente solicitações para vários back-ends, atuando como um balanceador de carga .

Daniel Vassallo
fonte
17

Eu uso JSONP.

Basicamente, você adiciona

<script src="http://..../someData.js?callback=some_func"/>

na sua página.

some_func () deve ser chamado para que você seja notificado de que os dados estão.

Nicolas Viennot
fonte
7
O JSONP tem dois problemas: a) Você está adicionando uma tag de script ao domínio de destino. Eles podem enviar qualquer coisa de volta, mesmo javascript regular (ataque XSS). Portanto, você realmente precisa confiar neles para não fazer coisas ruins ou serem invadidos b) Qualquer outra página da Web pode adicionar a mesma tag de script e roubar os dados, para nunca usar o JSONP para dados particulares.
Erlend
1
@ Erlend: Qualquer informação veiculada na web pode ser recuperada por qualquer pessoa (a menos que seja necessária autenticação adequada). O formato exato de como essas informações são apresentadas não torna isso melhor ou pior, nem mesmo se for JSONP.
T-Bull
2
@ T-Bull: O problema é que a autenticação adequada é impossível com o JSONP. Um usuário efetua login no site A e depois vai para o site B, que carrega dados de A usando uma tag de script JSONP. Como é bom e bom. Em seguida, o usuário é levado a visitar o site maligno C, que também usa uma tag de script JSONP para carregar dados de A. Portanto, como o usuário é autenticado com A, o proprietário de C agora pode roubar os dados dos usuários de A. E isso é mesmo se o usuário usou a autenticação de dois fatores para se autenticar com A. O problema é que o JSONP é altamente inseguro. E JSONP não é apresentação. É uma transferência de dados insegura.
Erlend
1
JSONP suporta apenas HTTP GET.
Opionar em
O arquivo .js que isso representa -> "http: //..../someData.js.... Estou tentando ler o domínio de outro site do lado do cliente e preciso burlar a política de mesma origem .
CS_2013
13

O AnyOrigin não funcionou bem em alguns sites https, então acabei de escrever uma alternativa de código aberto chamada Whateverorigin.org que parece funcionar bem com https.

Código no github .

ripper234
fonte
@ DavidTitarenco - fiquei louco tentando entender algumas das coisas que acontecem na barriga de alguém. Felizmente, encontrei um post que ajudou, e agora o próximo cara terá um site de teste em funcionamento, se ele precisar.
ripper234
@neoascetic - corrigido o uso ... o URL precisa ser codificado agora.
ripper234
12

A maneira mais recente de superar a política de mesma origem que eu encontrei é http://anyorigin.com/

O site foi criado para você fornecer apenas um URL e gerar código javascript / jquery para você, permitindo que você obtenha o html / data, independentemente de sua origem. Em outras palavras, torna qualquer URL ou página da Web uma solicitação JSONP.

Eu achei bastante útil :)

Aqui está um exemplo de código javascript de anyorigin:

$.getJSON('http://anyorigin.com/get?url=google.com&callback=?', function(data){
    $('#output').html(data.contents);
});
rk1s
fonte
Embora ele me deu alguns problemas com sites https, de modo a verificar a minha alternativa open source abaixo: stackoverflow.com/questions/3076414/...
ripper234
13
O que significa que: a) anyorigin poderá ler todos os seus dados transferidos através do tem b) anyorigin pode XSS no seu site, ler todos os dados no seu site e entregar malware aos seus usuários (o que acontece se algum hacker for invadido?)
Erlend
@ Erlend - bifurque o Whateverorigin e hospede-o em seu próprio servidor. O código é trivial, portanto, você pode revisá-lo para garantir que não ocorram explorações.
ripper234
3

O JSONP vem à mente:

JSONP ou "JSON com preenchimento" é um complemento ao formato de dados JSON base, um padrão de uso que permite que uma página solicite e use JSON de forma mais significativa de um servidor que não seja o servidor principal. JSONP é uma alternativa a um método mais recente chamado Compartilhamento de Recursos de Origem Cruzada.

Sarfraz
fonte
Veja meu comentário para JSONP acima. Não é uma boa opção para dados privados.
Erlend
1

Pessoalmente, window.postMessageé a maneira mais confiável que eu encontrei para navegadores modernos. Você precisa fazer um pouco mais de trabalho para se certificar de não se deixar abrir para ataques de XSS, mas é uma troca razoável.

Também existem vários plug-ins para os kits de ferramentas Javascript populares, window.postMessageque oferecem funcionalidade semelhante aos navegadores mais antigos usando os outros métodos discutidos acima.

Justin Niessner
fonte
1

Bem, eu usei curl no PHP para contornar isso. Eu tenho um serviço da web em execução na porta 82.

<?php

$curl = curl_init();
$timeout = 30;
$ret = "";
$url="http://localhost:82/put_val?val=".$_GET["val"];
curl_setopt ($curl, CURLOPT_URL, $url);
curl_setopt ($curl, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt ($curl, CURLOPT_MAXREDIRS, 20);
curl_setopt ($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt ($curl, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5");
curl_setopt ($curl, CURLOPT_CONNECTTIMEOUT, $timeout);
$text = curl_exec($curl);
echo $text;

?>

Aqui está o javascript que faz a chamada para o arquivo PHP

function getdata(obj1, obj2) {

    var xmlhttp;

    if (window.XMLHttpRequest)
            xmlhttp=new XMLHttpRequest();
    else
            xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");

    xmlhttp.onreadystatechange=function()
    {
        if (xmlhttp.readyState==4 && xmlhttp.status==200)
        {
                document.getElementById("txtHint").innerHTML=xmlhttp.responseText;
        }
    }
    xmlhttp.open("GET","phpURLFile.php?eqp="+obj1+"&val="+obj2,true);
    xmlhttp.send();
}

Meu HTML é executado no WAMP na porta 80. Então, lá vamos nós, a mesma política de origem foi contornada :-)

harihb
fonte