Ich lade ein </code> in meiner HTML-Seite und versuche, die Elemente darin mit JavaScript zu bearbeiten, aber wenn ich meinen Code ausführen möchte, erhalte ich den folgenden Fehler:</p> <blockquote> <p>Sicherheitsfehler: Ein Frame mit der Herkunft "http://www.example.com" wurde daran gehindert, auf einen Frame mit einer anderen Herkunft zuzugreifen.</p> </blockquote> <p>Wie kann ich auf die Elemente im Frame zugreifen?</p> <p>Ich verwende diesen Code zum Testen, aber vergeblich:</p> <pre class="lang-js prettyprint-override"><code>$(document).ready(function() { var iframeWindow = document.getElementById("my-iframe-id").contentWindow; iframeWindow.addEventListener("load", function() { var doc = iframe.contentDocument || iframe.contentWindow.document; var target = doc.getElementById("my-target-id"); target.innerHTML = "Gefunden!"; }); }); </code></pre></x-turndown>
Antworten
Zu viele Anzeigen?Same-origin policy
Sie können nicht auf ein </code> mit einer anderen Herkunft über JavaScript zugreifen, es wäre ein großer Sicherheitsfehler, wenn dies möglich wäre. Für die <a href="https://developer.mozilla.org/de/docs/Web/Security/Same-origin_policy" rel="noreferrer">Same-Origin-Richtlinie</a> blockieren Browser Skripte, die versuchen, auf ein Frame mit einer anderen Herkunft zuzugreifen.</p> <p>Eine Herkunft gilt als unterschiedlich, wenn mindestens einer der folgenden Teile der Adresse nicht übereinstimmt:</p> <pre><b>Protokoll</b>://<b>Hostname</b>:<b>Port</b>/...</pre> <p>Protokoll, Hostname und Port müssen die gleichen wie Ihre Domäne sein, wenn Sie auf ein Frame zugreifen möchten.</p> <p><sup>HINWEIS: Obwohl heutzutage größtenteils nicht mehr verwendet, ist bekannt, dass der Internet Explorer diese Regel nicht streng einhält, siehe <a href="https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy#Exceptions_in_Internet_Explorer" rel="noreferrer">hier</a> für Details.</sup></p> <h3>Beispiele</h3> <p>Hier ist, was passieren würde, wenn Sie versuchen würden, auf die folgenden URLs von <code>http://www.example.com/home/index.html</code> zuzugreifen:</p> <pre class="lang-none prettyprint-override"><code>URL ERGEBNIS http://www.example.com/home/other.html -> Erfolg http://www.example.com/dir/inner/another.php -> Erfolg http://www.example.com:80 -> Erfolg (Standardport für HTTP) http://www.example.com:2251 -> Fehler: Unterschiedlicher Port http://data.example.com/dir/other.html -> Fehler: Unterschiedlicher Hostname https://www.example.com/home/index.html:80 -> Fehler: Unterschiedliches Protokoll ftp://www.example.com:21 -> Fehler: Unterschiedliches Protokoll & Port https://google.com/search?q=james+bond -> Fehler: Unterschiedliches Protokoll, Port & Hostname </code></pre> <h2>Umgehungslösung</h2> <p>Auch wenn die Same-Origin-Richtlinie Skripte daran hindert, auf den Inhalt von Websites mit einer anderen Herkunft zuzugreifen, <strong>wenn Sie beide Seiten besitzen, können Sie dieses Problem umgehen, indem Sie <a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage" rel="noreferrer"><code>window.postMessage</code></a> und das zugehörige <code>message</code> Ereignis verwenden</strong>, um Nachrichten zwischen den beiden Seiten zu senden, wie folgt:</p> <ul> <li><p>In Ihrer Hauptseite:</p> <pre><code>const frame = document.getElementById('Ihre-Frame-ID'); frame.contentWindow.postMessage(/* beliebige Variable oder Objekt hier */, 'https://Ihre-Zweite-Seite.example'); </code></pre> <p>Das zweite Argument für <code>postMessage()</code> kann <code>'*'</code> sein, um keine Präferenz hinsichtlich der Herkunft des Ziels anzugeben. Wenn möglich, sollte immer eine Zielherkunft angegeben werden, um zu vermeiden, dass die Daten, die Sie senden, an eine andere Website weitergegeben werden.</p> </li> <li><p>In Ihrem <code><iframe></code> (enthalten in der Hauptseite):</p> <pre><code>window.addEventListener('message', event => { // WICHTIG: Überprüfen Sie die Herkunft der Daten! if (event.origin === 'https://Ihre-Erste-Seite.example') { // Die Daten wurden von Ihrer Seite gesendet. // Die mit postMessage gesendeten Daten werden in event.data gespeichert: console.log(event.data); } else { // Die Daten wurden NICHT von Ihrer Seite gesendet! // Seien Sie vorsichtig! Verwenden Sie sie nicht. Dieser else-Zweig dient lediglich der Klarheit, normalerweise sollte er nicht benötigt werden. return; } }); </code></pre> </li> </ul> <p>Diese Methode kann in <strong>beiden Richtungen</strong> angewendet werden, indem auch in der Hauptseite ein Listener erstellt wird und Antworten vom Frame empfangen werden. Die gleiche Logik kann auch in Pop-ups und praktisch jedem von der Hauptseite generierten neuen Fenster (z.B. unter Verwendung von <a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/open" rel="noreferrer"><code>window.open()</code></a>) implementiert werden, ohne Unterschiede.</p> <h2>Deaktivierung der Same-Origin-Richtlinie in <em>Ihrem</em> Browser</h2> <p>Es gibt bereits einige gute Antworten zu diesem Thema (ich habe sie gerade beim Googeln gefunden), daher werde ich für die Browser, in denen dies möglich ist, die entsprechende Antwort verlinken. Bitte bedenken Sie jedoch, dass <strong>das Deaktivieren der Same-Origin-Richtlinie nur <em>Ihren</em> Browser betrifft</strong>. Außerdem gewährt das Ausführen eines Browsers mit deaktivierten Same-Origin-Sicherheitseinstellungen <em>jeder</em> Website Zugriff auf ressourcenübergreifende Ressourcen, daher <strong>ist dies sehr unsicher und sollte NIE gemacht werden, wenn Sie nicht genau wissen, was Sie tun (z.B. für Entwicklungszwecke)</strong>.</p> <ul> <li><a href="https://stackoverflow.com/q/3102819/3889449">Google Chrome</a></li> <li><a href="https://stackoverflow.com/q/17088609/3889449">Mozilla Firefox</a></li> <li><a href="https://stackoverflow.com/q/4556429/3889449">Safari</a></li> <li><a href="https://stackoverflow.com/q/7543678/3889449">Opera</a>: gleich wie Chrome</li> <li>Microsoft Edge: gleich wie Chrome</li> <li>Brave: gleich wie Chrome</li> <li>Microsoft Edge (alte nicht-Chromium-Version): <a href="https://superuser.com/q/1020612/591004">nicht möglich</a></li> <li><a href="https://stackoverflow.com/q/20947359/3889449">Microsoft Internet Explorer</a></li> </ul></x-turndown>
Als Ergänzung zu Marcos Bonellis Antwort: Derzeit ist der beste Weg, um zwischen Frames / IFrames zu interagieren, die Verwendung von window.postMessage
, von allen Browsern unterstützt
Überprüfen Sie den Webserver der Domain http://www.example.com
auf die Konfiguration von X-Frame-Options
Es handelt sich um ein Sicherheitsmerkmal, das entwickelt wurde, um Clickjacking-Angriffe zu verhindern.
Wie funktioniert Clickjacking?
- Die betrügerische Seite sieht genau wie die Opferseite aus.
- Dann werden die Benutzer getäuscht, ihre Benutzername und Passwort einzugeben.
Technisch gesehen hat die böswillige Seite ein iframe
mit der Quelle zur Opferseite.
<input id="username" type="text" style="display: none;"/>
<input id="password" type="text" style="display: none;"/>
<script>
//Einige JS-Code, der den Benutzernamen und die Eingabe des Benutzers von innerhalb des iframes clickjackt...
<script/>
<html>
</code></pre>
<h2>Wie funktioniert das Sicherheitsmerkmal?</h2>
<p>Wenn Sie möchten, dass Webserver-Anfragen nicht innerhalb eines <code>iframe</code> gerendert werden, fügen Sie das <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options" rel="nofollow noreferrer">x-frame-options</a> hinzu</p>
<blockquote>
<p>X-Frame-Options DENY</p>
</blockquote>
<p>Die Optionen sind:</p>
<ol>
<li><code>SAMEORIGIN</code>: erlauben Sie nur meiner eigenen Domain, mein HTML innerhalb eines iframes zu rendern.</li>
<li><code>DENY</code>: erlauben Sie nicht, dass mein HTML innerhalb eines iframes gerendert wird</li>
<li><code>ALLOW-FROM https://example.com/</code>: erlauben Sie einer spezifischen Domain, mein HTML innerhalb eines iframes zu rendern</li>
</ol>
<p>Dies ist ein Beispiel für die IIS-Konfiguration:</p>
<pre><code> <httpProtocol>
<customHeaders>
<add name="X-Frame-Options" value="SAMEORIGIN" />
</customHeaders>
</httpProtocol>
</code></pre>
<h2>Die Lösung für die Frage</h2>
<p>Wenn der Webserver das Sicherheitsmerkmal aktiviert hat, kann dies einen SecurityError auf der Clientseite verursachen, wie es soll.</p></x-turndown>
Für mich wollte ich einen 2-Wege-Handshake implementieren, das bedeutet:
- das übergeordnete Fenster wird schneller geladen als das iFrame
- das iFrame sollte sofort mit dem übergeordneten Fenster sprechen, sobald es bereit ist
- das übergeordnete Fenster ist bereit, die iFrame-Nachricht zu empfangen und zu antworten
dieser Code wird verwendet, um das White-Label im iFrame mit [CSS-Benutzerdefinierte Eigenschaft] festzulegen
code:
iFrame
$(function() {
window.onload = function() {
// Listener erstellen
function receiveMessage(e) {
document.documentElement.style.setProperty('--header_bg', e.data.wl.header_bg);
document.documentElement.style.setProperty('--header_text', e.data.wl.header_text);
document.documentElement.style.setProperty('--button_bg', e.data.wl.button_bg);
//alert(e.data.data.header_bg);
}
window.addEventListener('message', receiveMessage);
// Eltern aufrufen
parent.postMessage("GetWhiteLabel","*");
}
});
Eltern
$(function() {
// Listener erstellen
var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
var eventer = window[eventMethod];
var messageEvent = eventMethod == "attachEvent" ? "onmessage" : "message";
eventer(messageEvent, function (e) {
// An das Kind (iFrame) zurückschreiben
document.getElementById('wrapper-iframe').contentWindow.postMessage(
{
event_id: 'white_label_message',
wl: {
header_bg: $('#Header').css('background-color'),
header_text: $('#Header .HoverMenu a').css('color'),
button_bg: $('#Header .HoverMenu a').css('background-color')
}
},
'*'
);
}, false);
});
natürlich können Sie die Ursprünge und den Text begrenzen, dies ist ein leicht zu bearbeitender Code
ich fand dieses Beispiel hilfreich:
[Cross-Domain Messaging Mit postMessage]
Es gibt tatsächlich einen Workaround für spezifische Szenarien.
Wenn Sie zwei Prozesse auf demselben Domain, aber unterschiedlichen Ports laufen haben, können die zwei Windows ohne Einschränkungen interagieren. (z.B. localhost:3000
& localhost:2000
). Um dies zum Funktionieren zu bringen, muss jedes Fenster seine Domain auf den gemeinsamen Ursprung ändern:
document.domain = 'localhost'
Dies funktioniert auch im Szenario, dass Sie mit verschiedenen Subdomains auf demselben zweiten Domain arbeiten, d.h. Sie sind auf john.site.example
und versuchen auf peter.site.example
oder einfach site.example
zuzugreifen
document.domain = 'site.example'
Indem Sie document.domain
explizit setzen; wird der Browser den Hostnamenunterschied ignorieren und die Windows können als aus derselben Ursprung kommend behandelt werden. Jetzt können Sie in einem Elternfenster auf das iframe zugreifen: frame.contentWindow.document.body.classList.add('happyDev')
- See previous answers
- Weitere Antworten anzeigen