Diese Richtlinie legt wichtige Einschränkungen für den Seiteninhalt fest, auf den JavaScript-Code zugreifen kann, d. h. JavaScript kann nur auf Inhalte in derselben Domäne zugreifen wie das Dokument, das ihn enthält.
Die JavaScript-Sicherheitsstrategie ist besonders wichtig, wenn Multi-Iframe- oder Multi-Window-Programmierung sowie Ajax-Programmierung durchgeführt werden. Gemäß dieser Richtlinie kann JavaScript-Code, der in Seiten unter baidu.com enthalten ist, nicht auf Seiteninhalte unter dem Domainnamen google.com zugreifen. Auch Seiten zwischen verschiedenen Subdomains können nicht über JavaScript-Code aufeinander zugreifen. Die Auswirkung auf Ajax besteht darin, dass über XMLHttpRequest implementierte Ajax-Anfragen keine Anfragen an verschiedene Domänen senden können. Beispielsweise können Seiten unter abc.example.com keine Ajax-Anfragen an def.example.com usw. senden.
Bei einer detaillierten Front-End-Programmierung sind jedoch zwangsläufig domänenübergreifende Vorgänge erforderlich. Derzeit scheint die „Same-Origin-Politik“ zu streng zu sein. In diesem Artikel werden einige für die domänenübergreifende Nutzung erforderliche Technologien zu diesem Thema zusammengefasst.
Im Folgenden diskutieren wir die domänenübergreifende Technologie in zwei Situationen: Zuerst diskutieren wir die domänenübergreifende Technologie in verschiedenen Subdomänen und dann diskutieren wir die domänenübergreifende Technologie in völlig unterschiedlichen Domänen.
(1) Domänenübergreifende Technologien in verschiedenen Subdomänen.
Wir werden zwei Fragen separat diskutieren: Die erste Frage ist, wie man JavaScript-Aufrufe über verschiedene Subdomains hinweg durchführt; die zweite Frage ist, wie man Ajax-Anfragen an verschiedene Subdomains sendet.
Lassen Sie uns zunächst das erste Problem lösen. Angenommen, es gibt zwei verschiedene Subdomains unter der Domain example.com: abc.example.com und def.example.com. Angenommen, es gibt eine Seite unter def.example.com, die eine JavaScript-Funktion definiert:
Auf diese Weise werden die beiden Seiten zur gleichen Domäne und die vorherigen Aufrufe können normal ausgeführt werden.
Hier ist zu beachten, dass das document.domain-Attribut einer Seite nur auf einen Domänennamen einer höheren Ebene (mit Ausnahme des Domänennamens der ersten Ebene) festgelegt werden kann, nicht jedoch auf eine Unterdomäne tiefer als der aktuelle Domänenname. Beispielsweise kann die Domäne der Seite abc.example.com nur auf example.com und nicht auf sub.abc.example.com festgelegt werden, und natürlich kann sie nicht auf den Domänennamen der ersten Ebene „com“ festgelegt werden.
Das obige Beispiel beschreibt den Fall, in dem zwei Seiten zu einer verschachtelten Iframe-Beziehung gehören. Wenn die beiden Seiten eine offene und eine geöffnete Beziehung haben, ist das Prinzip genau das gleiche.
Lösen wir das zweite Problem: Wie sendet man Ajax-Anfragen an verschiedene Subdomains?
Normalerweise verwenden wir Code ähnlich dem folgenden, um ein XMLHttpRequest-Objekt zu erstellen:
Angenommen, der obige Code ist in einer Seite unter dem Domainnamen abc.example.com enthalten, kann die GET-Anfrage ohne Probleme erfolgreich gesendet werden. Wenn wir nun jedoch eine Anfrage an def.example.com senden, tritt ein domänenübergreifendes Problem auf und die JavaScript-Engine löst eine Ausnahme aus.
Die Lösung besteht darin, eine domänenübergreifende Datei unter der Domäne def.example.com zu platzieren, vorausgesetzt, sie heißt crossdomain.html. Anschließend wird die Definition der vorherigen newRequest-Funktion in diese domänenübergreifende Datei verschoben Dokument wie zuvor. Fügen Sie oben in der Datei crossdomain.html und auf der Seite, die Ajax unter der Domäne abc.example.com aufruft, hinzu:
(2) Domänenübergreifende Technologien in völlig unterschiedlichen Domänen.
Wenn die Top-Level-Domain-Namen unterschiedlich sind, beispielsweise example1.com und example2.com im Frontend über JavaScript kommunizieren möchten, ist die erforderliche Technologie komplizierter.
Bevor wir die domänenübergreifende Technologie verschiedener Domänen erläutern, möchten wir zunächst klarstellen, dass die im Folgenden besprochene Technologie auch auf die vorherige Situation über verschiedene Unterdomänen hinweg anwendbar ist, da das Überqueren verschiedener Unterdomänen der Fall ist nur ein Sonderfall domänenübergreifender Probleme. Natürlich kann der Einsatz der richtigen Technologie unter den richtigen Umständen eine bessere Effizienz und höhere Stabilität gewährleisten.
Kurz gesagt, je nach domänenübergreifenden Anforderungen können domänenübergreifende Technologien in die folgenden Kategorien eingeteilt werden:
1. Domänenübergreifende JSONP-GET-Anforderung
2 iframe
3. Flash-domänenübergreifende HTTP-Anfrage
4. window.postMessage
Im Folgenden werden verschiedene Technologien im Detail vorgestellt.
1. JSONP.
Die Methode zum Senden von HTTP-Anfragen an verschiedene Domänen durch Erstellen von <script>-Knoten wird als JSONP bezeichnet. Diese Technologie kann das Problem der domänenübergreifenden Übermittlung von Ajax-Anfragen lösen. Das Funktionsprinzip von JSONP ist wie folgt: <br> Angenommen, eine GET-Anfrage wird an http://example2.com/getinfo.php auf der Seite http://example1.com/index.php gesendet, können wir die einfügen Folgender JavaScript-Code: Platzieren Sie ihn auf der Seite http://example1.com/index.php, um ihn zu implementieren: <br></p>
<div class="codetitle">
<span><a style="CURSOR: pointer" data="91817" class="copybut" id="copybut91817" onclick="doCopy('code91817')"><u>Kopieren Sie den Code</u></a></span> Der Der Code lautet wie folgt:</div>
<div class="codebody" id="code91817">var eleScript= document.createElement("script");<br>eleScript.type = "text/javascript";<br>eleScript.src = "http://example2. com/getinfo.php"; <br>document.getElementsByTagName("HEAD")[0].appendChild(eleScript);</div>
<p>当GET请求从http://example2.com/getinfo.php返回时,可以返回一段JavaScript代码,这段代码会自动执行,可以用来负责调用http://example1.com/index.php页面中的一个callback函数。<br><br>JSONP的优点是:它不像XMLHttpRequest对象实现的Ajax请求那样受到同源策略的限制;它的兼容性更好,在更加古老的浏览器中都可以运行,不需要XMLHttpRequest或ActiveX的支持;并且在请求完毕后可以通过调用callback的方式回传结果。<br><br>JSONP的缺点则是:它只支持GET请求而不支持POST等其它类型的HTTP请求;它只支持跨域HTTP请求这种情况,不能解决不同域的两个页面之间如何进行JavaScript调用的问题。</p>
<p><strong>2. 通过iframe实现跨域。<br><br></strong>iframe跨域的方式,功能强于JSONP,它不仅能用来跨域完成HTTP请求,还能在前端跨域实现JavaScript调用。因此,完全不同域的跨域问题,通常采用iframe的方式来解决。<br><br>与JSONP技术通过创建<script>节点向不同的域提交GET请求的工作方式类似,我们也可以通过在http://example1.com/index.php页面中创建指向http://example2.com/getinfo.php的iframe节点跨域提交GET请求。然而,请求返回的结果无法回调http://example1.com/index.php页面中的callback函数,因为受到“同源策略”的影响。<br><br>为了解决这个问题,我们需要在example1.com下放置一个跨域文件,比如路径是http://example1.com/crossdomain.html。<br><br>当http://example2.com/getinfo.php这个请求返回结果的时候,它大体上有两个选择。<br>第一个选择是,它可以在iframe中做一个302跳转,跳转到跨域文件http://example1.com/crossdomain.html,同时将返回结果经过URL编码之后作为参数缀在跨域文件URL后面,例如http://example1.com/crossdomain.html?result=<URL-Encoding-Content>。<br><br>另一个选择是,它可以在返回的页面中再嵌入一个iframe,指向跨域文件,同时也是将返回结果经过URL编码之后作为参数缀在跨域文件URL后面。<br><br>在跨域文件中,包含一段JavaScript代码,这段代码完成的功能,是从URL中提取结果参数,经过一定处理后调用原来的http://example1.com/index.php页面中的一个预先约定好的callback函数,同时将结果参数传给这个函数。http://example1.com/index.php页面和跨域文件是在同一个域下的,因此这个函数调用可以通过。跨域文件所在iframe和原来的http://example1.com/index.php页面的关系,在前述第一种选择下,后者是前者的父窗口,在第二种选择下,后者是前者的父窗口的父窗口。<br><br>根据前面的叙述,有了跨域文件之后,我们就可以实现通过iframe方式在不同域之间进行JavaScript调用。这个调用过程可以完全跟HTTP请求无关,例如有些站点可以支持动态地调整在页面中嵌入的第三方iframe的高度,这其实是通过在第三方iframe里面检测自己页面的高度变化,然后通过跨域方式的函数调用将这个变化告知父窗口来完成的。<br><br>既然利用iframe可以实现跨域JavaScript调用,那么跨域提交POST请求等其它类型的HTTP请求就不是难事。例如我们可以跨域调用目标域的JavaScript代码在目标域下提交Ajax请求(GET/POST/etc.),然后将返回的结果再跨域传原来的域。<br><br>使用iframe跨域,优点是功能强大,支持各种浏览器,几乎可以完成任何跨域想做的事情;缺点是实现复杂,要处理很多浏览器兼容问题,并且传输的数据不宜过大,过大了可能会超过浏览器对URL长度的限制,要考虑对数据进行分段传输等。</p>
<p><strong>3. 利用flash实现跨域HTTP请求<br></strong><br>据称,flash在浏览器中的普及率高达90%以上。<br><br>flash代码和JavaScript代码之间可以互相调用,并且flash的“安全沙箱”机制与JavaScript的安全机制并不尽相同,因此,我们可以利用flash来实现跨域提交HTTP请求(支持GET/POST等)。<br>例如,我们用浏览器访问http://example1.com/index.php这个页面,在这个页面中引用了http://example2.com/flash.swf这个flash文件,然后在flash代码中向http://example3.com/webservice.php发送HTTP请求。<br><br>这个请求能否被成功发送,取决于在example3.com的根路径下是否放置了一个crossdomain.xml以及这个crossdomain.xml的配置如何。flash的“安全沙箱”会保证:仅当example3.com服务器在根路径下确实放置了crossdomain.xml文件并且在这个文件中配置了允许接受来自example2.com的flash的请求时,这个请求才能真正成功。下面是一个crossdomain.xml文件内容的例子:</p>
<p></p>
<div class="codetitle">
<span><a style="CURSOR: pointer" data="91153" class="copybut" id="copybut91153" onclick="doCopy('code91153')"><u>Code kopieren</u></a></span> Der Code lautet wie folgt:</div>
<div class="codebody" id="code91153">
<br><?xml version="1.0" ?> <br><cross-domain-policy><br> <allow-access-from domain="example2.com" /><br></cross-domain-policy><br>
</div>
<p><strong>4. window.postMessage<br></strong> window.postMessage ist eine neue Funktion, die von HTML5, der nächsten Version des HTML-Standards, unterstützt wird. Aufgrund der rasanten Weiterentwicklung der aktuellen Internettechnologie wird die Nachfrage nach browserübergreifender domänenübergreifender Kommunikation immer stärker, und der HTML-Standard berücksichtigt endlich die domänenübergreifende Kommunikation. Doch derzeit ist HTML5 noch ein Entwurf. <br> window.postMessage ist eine sichere Methode, um eine direkte domänenübergreifende Kommunikation zu erreichen. Allerdings unterstützen es derzeit nicht alle Browser. Nur Firefox 3, Safari 4 und IE8 können diesen Aufruf unterstützen. <br><br>Die Aufrufmethode zum Senden von Nachrichten an andere Fenster lautet ungefähr wie folgt:<br></p>
<div class="codetitle">
<span><a style="CURSOR: pointer" data="66586" class="copybut" id="copybut66586" onclick="doCopy('code66586')"><u>Kopieren Sie den Code</u></a></span> Der Code lautet wie folgt:</div>
<div class="codebody" id="code66586">otherWindow.postMessage(message, targetOrigin);</div>
<br>Im Empfangsfenster müssen Sie eine Ereignisverarbeitungsfunktion einrichten, um die gesendete Nachricht zu empfangen: <br> <div class="codetitle">
<span><a style="CURSOR: pointer" data="40287" class="copybut" id="copybut40287" onclick="doCopy('code40287')"><u>Code kopieren</u></a></span> Der Code lautet wie folgt:</div>
<div class="codebody" id="code40287">window.addEventListener("message", retainMessage, false);<br>function keepMessage(event) {<br> if (event .origin !== "http://example.org:8080") return;<br>}</div>
<br>Die Nachricht enthält drei Attribute: Daten, Ursprung (trägt die tatsächlichen Informationen der Domäne, in der sich das Sendefenster befindet) und Quelle (Stellt das Handle des Sendefensters dar). <br><br>Sicherheitsaspekte: Bei Verwendung von window.postMessage müssen Sie die Ursprungs- und Quellattribute der Nachricht verwenden, um die Identität des Absenders zu überprüfen, da sonst XSS-Schwachstellen auftreten. <br><br>window.postMessage ist genauso leistungsfähig wie die von iframe implementierte domänenübergreifende Funktion, einfach zu verwenden und effizienter. Der Nachteil besteht jedoch darin, dass es derzeit hinsichtlich der Browserkompatibilität verbessert werden muss. <br><br>Was dem Originaltext hinzugefügt werden muss, ist, dass unter IE6 und IE7 die Schwachstelle des IE-Openers, der einem Objekt oder einer Funktion zugewiesen werden kann, ausgenutzt werden kann und eine ergänzende Lösung für die postMessage-Lösung bereitgestellt wird: <br>Hauptseite:
<p></p>
<div class="codetitle">
<span><a style="CURSOR: pointer" data="92626" class="copybut" id="copybut92626" onclick="doCopy('code92626')"><u>Code kopieren</u></a></span> Der Code lautet wie folgt:</div>
<div class="codebody" id="code92626">
<br><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" ><br><html xmlns="http://www.w3.org/1999/xhtml"><br><head><br> <title>CrossDomain</title><br>< ;/head><br><body><br> <iframe src="http://sh-tanzhenlin/CrossDomain-child.html"<BR> frameborder="0" sichtbar="false" height=" 0" width="0" id="ifrChild"></iframe><br><br> <script type="text/javascript"><br> var child = document.getElementById("ifrChild" );<br> var openerObject = {<br> funcInParent:function(arg){<br> Alert(arg);<br> ');<br> }<br> }<br><br> if(! 'v1' && !'1'[0]){ //Testbrowser ist ie6 oder ie7 <br> //crack<br> child.contentWindow.opener = openerObject;<br> openerObject.funcInIframe('Daten von der übergeordneten Seite') ;<br> }<br> </script>