Moyens de contourner la politique de même origine

150

La même politique d'origine

Je voulais créer un wiki communautaire concernant les politiques HTML / JS de même origine pour aider, espérons-le, tous ceux qui recherchent ce sujet. C'est l'un des sujets les plus recherchés sur SO et il n'y a pas de wiki consolidé pour cela, alors j'y vais :)

La même politique d'origine empêche un document ou un script chargé à partir d'une origine d'obtenir ou de définir les propriétés d'un document à partir d'une autre origine. Cette politique remonte à Netscape Navigator 2.0.

Quelles sont certaines de vos façons préférées de contourner les politiques de même origine?

Veuillez garder des exemples verbeux et de préférence également relier vos sources.

David Titarenco
la source
4
bonne idée .. Vous devriez mettre vos exemples en réponse (s) cependant; dans l'état actuel des choses, ils rendent la question assez volumineuse
Shog9
1
Vous devez également ajouter une liste des implications de sécurité pour chaque approche. JSONP est hautement non sécurisé pour les données privées.
Erlend
Pourquoi la clôture? Cette question (wiki) a été très utile au cours des 2 dernières années. De plus, de nombreuses réponses sont étayées par des références. Une explication serait appréciée car une not constructivebalise semble tout à fait absurde. A voté pour la réouverture.
David Titarenco

Réponses:

84

La document.domainméthode

  • Type de méthode: iframe .

Notez qu'il s'agit d'une méthode iframe qui définit la valeur de document.domain sur un suffixe du domaine actuel. Si tel est le cas, le domaine le plus court est utilisé pour les contrôles d'origine ultérieurs. Par exemple, supposons qu'un script dans le document à http://store.company.com/dir/other.htmlexécute l'instruction suivante:

document.domain = "company.com";

Une fois cette instruction exécutée, la page passera la vérification d'origine avec http://company.com/dir/page.html. Cependant, par le même raisonnement, company.com ne pouvait pas mettre document.domain à othercompany.com.

Avec cette méthode, vous seriez autorisé à exécuter du javascript à partir d'une iframe provenant d'un sous-domaine sur une page provenant du domaine principal. Cette méthode n'est pas adaptée aux ressources inter-domaines car les navigateurs comme Firefox ne vous permettront pas de changer le document.domainen un domaine complètement étranger.

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

La méthode de partage de ressources cross-origin

  • Type de méthode: AJAX .

Cross-Origin Resource Sharing (CORS) est une ébauche de travail du W3C qui définit la manière dont le navigateur et le serveur doivent communiquer lors de l'accès aux sources entre les origines. L'idée de base derrière CORS est d'utiliser des en-têtes HTTP personnalisés pour permettre au navigateur et au serveur de se connaître suffisamment pour déterminer si la demande ou la réponse doit réussir ou échouer.

Pour une requête simple, qui utilise soit GETou POSTsans en-têtes personnalisés et dont le corps est text/plain, la requête est envoyée avec un en-tête supplémentaire appelé Origin. L'en-tête Origin contient l'origine (protocole, nom de domaine et port) de la page demandeuse afin que le serveur puisse facilement déterminer s'il doit ou non servir une réponse. Un exemple d'en- Origintête pourrait ressembler à ceci:

Origin: http://www.stackoverflow.com

Si le serveur décide que la demande doit être autorisée, il envoie un en- Access-Control-Allow-Origintête faisant écho à la même origine qui a été envoyée ou *s'il s'agit d'une ressource publique. Par exemple:

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

Si cet en-tête est manquant ou si les origines ne correspondent pas, le navigateur refuse la demande. Si tout va bien, le navigateur traite la demande. Notez que ni les demandes ni les réponses ne contiennent d'informations sur les cookies.

L'équipe Mozilla suggère dans son article sur CORS que vous devriez vérifier l'existence de la withCredentials propriété pour déterminer si le navigateur prend en charge CORS via XHR. Vous pouvez alors coupler avec l'existence de l' XDomainRequestobjet pour couvrir tous les navigateurs:

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();
}

Notez que pour que la méthode CORS fonctionne, vous devez avoir accès à n'importe quel type de mécanisme d'en-tête de serveur et ne pouvez pas simplement accéder à une ressource tierce.

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

La window.postMessageméthode

  • Type de méthode: iframe .

window.postMessage, lorsqu'il est appelé, provoque MessageEventl'envoi de a à la fenêtre cible lorsqu'un script en attente qui doit être exécuté se termine (par exemple, les gestionnaires d'événements restants s'il window.postMessageest appelé à partir d'un gestionnaire d'événements, les délais d'attente précédemment définis, etc.). Le MessageEventa le type message, une datapropriété qui est définie sur la valeur de chaîne du premier argument fourni à window.postMessage, une originpropriété correspondant à l'origine du document principal dans la fenêtre appelant window.postMessageau moment de l' window.postMessageappel, et une sourcepropriété qui est la fenêtre de qui window.postMessageest appelé.

Pour l'utiliser window.postMessage, un écouteur d'événement doit être attaché:

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

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

Et une receiveMessagefonction doit être déclarée:

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

L'iframe hors site doit également envoyer correctement les événements via postMessage:

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

Toute fenêtre peut accéder à cette méthode sur n'importe quelle autre fenêtre, à tout moment, quel que soit l'emplacement du document dans la fenêtre, pour lui envoyer un message. Par conséquent, tout écouteur d'événement utilisé pour recevoir des messages doit d'abord vérifier l'identité de l'expéditeur du message, en utilisant l'origine et éventuellement les propriétés source. Cela ne peut pas être sous- estimé : le fait de ne pas vérifier les propriétés originet éventuellement les sourcepropriétés permet des attaques de script intersite.

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

David Titarenco
la source
J'espère que je ne suis pas trop tard pour obtenir une réponse: par simple question, est-ce que localhost est TOUJOURS une exception? est-ce toujours interdit? dois-je arrêter de tester via mon hôte local?
Ayyash
1
Je ne sais pas pourquoi, mais lorsque j'ai défini: Access-Control-Allow-Origin: http://www.stackoverflow.com/au lieu de: Access-Control-Allow-Origin: http://www.stackoverflow.com(barre oblique à la fin de l'url), cela ne fonctionne pas dans Safari et FF mais fonctionne dans Chrome. Bien sûr, sans barre oblique fonctionne bien dans tous les navigateurs.
mtfk
1
Cela pourrait valoir la peine de faire savoir aux gens que la postMessageméthode ne fonctionne que pour les navigateurs qui la prennent en charge, car il s'agit d'un ajout HTML5. Ce plugin essaie d'en tenir compte. Je le mentionne simplement parce que j'apprends cela à la dure.
IronicMuffin
41

La méthode du proxy inverse

  • Type de méthode: Ajax

La configuration d'un proxy inverse simple sur le serveur permettra au navigateur d'utiliser des chemins relatifs pour les requêtes Ajax, tandis que le serveur agirait en tant que proxy vers n'importe quel emplacement distant.

Si vous utilisez mod_proxy dans Apache, la directive de configuration fondamentale pour configurer un proxy inverse est le ProxyPass. Il est généralement utilisé comme suit:

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

Dans ce cas, le navigateur pourrait demander en /ajax/web_service.xmltant qu'URL relative, mais le serveur le servirait en agissant en tant que proxy pour http://other-domain.com/ajax/web_service.xml.

Une caractéristique intéressante de cette méthode est que le proxy inverse peut facilement distribuer des requêtes vers plusieurs back-ends, agissant ainsi comme un équilibreur de charge .

Daniel Vassallo
la source
17

J'utilise JSONP.

En gros, vous ajoutez

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

sur ta page.

some_func () devrait être appelé afin que vous soyez averti que les données sont dans.

Nicolas Viennot
la source
7
JSONP a deux problèmes: a) Vous ajoutez une balise de script au domaine cible. Ils peuvent renvoyer n'importe quoi, même du javascript ordinaire (attaque XSS). Donc, vous devez vraiment leur faire confiance pour ne pas faire de mauvaises choses ou être piraté b) Toute autre page Web peut ajouter le même script-tag et voler les données, donc n'utilisez jamais JSONP pour des données privées.
Erlend
1
@Erlend: toute information diffusée sur le Web peut être récupérée par n'importe qui (sauf si une authentification appropriée est requise). Le format exact de la façon dont ces informations sont présentées ne rend pas cela meilleur ou pire, même s'il s'agit de JSONP.
T-Bull
2
@ T-Bull: Le problème est qu'une authentification correcte est impossible avec JSONP. Un utilisateur se connecte sur le site A, puis accède au site B, qui charge les données de A à l'aide d'une balise de script JSONP. Comme c'est bien. Ensuite, l'utilisateur est amené à visiter le site maléfique C, qui utilise également une balise de script JSONP pour charger les données de A. Donc, parce que l'utilisateur est authentifié avec A, le propriétaire de C peut maintenant voler les données des utilisateurs de A. Et c'est même si l'utilisateur a utilisé une authentification à deux facteurs pour s'authentifier auprès de A. Le problème est que JSONP est hautement non sécurisé. Et JSONP n'est pas une présentation. C'est un transfert de données non sécurisé.
Erlend
1
JSONP prend uniquement en charge HTTP GET.
opyate
Qu'est-ce que le fichier .js cela représente -> "http: //..../someData.js.... J'essaie de lire le dom à partir d'un autre site côté client et je dois contourner la politique de même origine .
CS_2013
13

AnyOrigin ne fonctionnait pas bien avec certains sites https, je viens donc d'écrire une alternative open source appelée whatorigin.org qui semble bien fonctionner avec https.

Code sur github .

ripper234
la source
@DavidTitarenco - cela m'a rendu fou d'essayer de comprendre certaines des choses qui se passaient dans le ventre de n'importe quelle origine. Heureusement, j'ai trouvé un article de blog qui m'a aidé, et maintenant le prochain gars aura un site de test fonctionnel s'il en a besoin.
ripper234 du
@neoascetic - correction de l'utilisation ... l'URL doit être encodée maintenant.
ripper234
12

Le moyen le plus récent de surmonter la politique de même origine que j'ai trouvé est http://anyorigin.com/

Le site est conçu pour que vous lui donniez n'importe quelle URL et il génère pour vous du code javascript / jquery qui vous permet d'obtenir le html / data, quelle que soit son origine. En d'autres termes, toute URL ou page Web est une requête JSONP.

Je l'ai trouvé assez utile :)

Voici un exemple de code javascript de n'importe quelle origine:

$.getJSON('http://anyorigin.com/get?url=google.com&callback=?', function(data){
    $('#output').html(data.contents);
});
rk1s
la source
Bien que cela m'ait
posé
13
Ce qui signifie que: a) anyorigin pourra lire toutes vos données transférées via tem b) anyorigin peut XSS votre site, lire toutes vos données sur votre site et livrer des logiciels malveillants à vos utilisateurs (que se passe-t-il si anyorigin est piraté?)
Erlend
@Erlend - branchez Whateverorigin et hébergez-le sur votre propre serveur. Le code est trivial, vous pouvez donc le consulter pour vous assurer qu'aucun exploit n'y est caché.
ripper234
3

Le JSONP vient à l'esprit:

JSONP ou "JSON with padding" est un complément au format de données JSON de base, un modèle d'utilisation qui permet à une page de demander et d'utiliser de manière plus significative JSON à partir d'un serveur autre que le serveur principal. JSONP est une alternative à une méthode plus récente appelée Partage de ressources inter-origines.

Sarfraz
la source
Voir mon commentaire sur JSONP ci-dessus. Pas un bon choix pour les données privées.
Erlend
1

Personnellement, window.postMessagec'est le moyen le plus fiable que j'ai trouvé pour les navigateurs modernes. Vous devez faire un peu plus de travail pour vous assurer de ne pas vous exposer aux attaques XSS, mais c'est un compromis raisonnable.

Il existe également plusieurs plugins pour les boîtes à outils Javascript populaires window.postMessagequi fournissent des fonctionnalités similaires aux navigateurs plus anciens en utilisant les autres méthodes décrites ci-dessus.

Justin Niessner
la source
1

Eh bien, j'ai utilisé curl en PHP pour contourner cela. J'ai un webservice fonctionnant dans le port 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;

?>

Voici le javascript qui fait l'appel au fichier 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();
}

Mon HTML fonctionne sur WAMP dans le port 80. Alors voilà, la même politique d'origine a été contournée :-)

harihb
la source