javascript - SecurityError: Blockerade ett fönster med ursprung från att få åtkomst till ett ramverk med annat ursprung
Jag laddar ett <iframe> på min HTML-sida och försöker komma åt elementen inom det med JavaScript, men när jag försöker köra min kod får jag följande fel:
SecurityError: Blockerade ett ramverk med ursprung "http://www.example.com" från att få åtkomst till ett ramverk med korsursprung.
Hur kan jag komma åt elementen i ramen?
Jag använder den här koden för testning, men förgäves:
$(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 = "Found it!";
});
});
Svar #1
Samursprångspolicy
Du kan inte komma åt ett <iframe> med en annan ursprung med JavaScript, det skulle vara ett stort säkerhetshål om du kunde göra det. På grund av samma-ursprungspolicyn blockerar webbläsare skript som försöker komma åt en ram med ett annat ursprung.
Ursprung anses vara annorlunda om minst en av följande delar av adressen inte upprätthålls:
protocol://hostname:port/...Protokoll, värdnamn och port måste vara samma som din domän om du vill komma åt en ram.
OBS: även om det mestadels inte används nuförtiden, är Internet Explorer känt för att inte strikt följa denna regel, se här för detaljer.
Exempel
Här är vad som skulle hända om du försöker komma åt följande URL:er från http://www.example.com/home/index.html
URL RESULT
http://www.example.com/home/other.html -> Success
http://www.example.com/dir/inner/another.php -> Success
http://www.example.com:80 -> Success (default port for HTTP)
http://www.example.com:2251 -> Failure: different port
http://data.example.com/dir/other.html -> Failure: different hostname
https://www.example.com/home/index.html:80 -> Failure: different protocol
ftp://www.example.com:21 -> Failure: different protocol & port
https://google.com/search?q=james+bond -> Failure: different protocol, port & hostname
Tillfällig lösning
Även om policyn för samma ursprung blockerar skript från att få åtkomst till innehållet på webbplatser med ett annat ursprung, om du äger båda sidorna kan du kringgå detta problem med window.postMessage och dess relaterade message-händelse för att skicka meddelanden mellan de två sidorna, så här:
På din huvudsida:
const frame = document.getElementById('your-frame-id'); frame.contentWindow.postMessage(/*any variable or object here*/, 'https://your-second-site.example');Det andra argumentet till
postMessage()kan vara'*'för att ange att man inte har någon preferens kring målets ursprung. Ett målursprung bör alltid anges när det är möjligt, för att undvika att data som skickas avslöjas till någon annan webbplats.I din
<iframe>(innehållen på huvudsidan):window.addEventListener('message', event => { // IMPORTANT: check the origin of the data! if (event.origin === 'https://your-first-site.example') { // The data was sent from your site. // Data sent with postMessage is stored in event.data: console.log(event.data); } else { // The data was NOT sent from your site! // Be careful! Do not use it. This else branch is // here just for clarity, you usually shouldn't need it. return; } });
Denna metod kan tillämpas i båda riktningarna, genom att skapa en lyssnare på huvud-sidan också, och ta emot svar från ramen. Samma logik kan också implementeras i popup-fönster och i princip vilket nytt fönster som helst som genereras av huvudsidan (t.ex. med window.open()) utan någon skillnad.
Inaktivera samma-origin-policy i din webbläsare
Det finns redan några bra svar om detta ämne (jag hittade dem bara genom att googla), så för de webbläsare där detta är möjligt, kommer jag att länka det relativa svaret. Men vänligen kom ihåg att att inaktivera same-origin-policy endast påverkar din webbläsare. Dessutom ger det att köra en webbläsare med säkerhetsinställningar för same-origin inaktiverade vilken som helst webbplats åtkomst till cross-origin-resurser, så det är mycket osäkert och bör ALDRIG göras om du inte exakt vet vad du gör (t.ex. för utvecklingsändamål).
- Google Chrome
- Mozilla Firefox
- Safari
- Opera: samma som Chrome
- Microsoft Edge: samma som Chrome
- Brave: samma som Chrome
- Microsoft Edge (gamla icke-Chromium-versionen): inte möjligt
- Microsoft Internet Explorer
Svar #2
Kompletterande Marco Bonellis svar: det bästa sättet idag att interagera mellan ramar/iframes är att använda window.postMessage, som stöds av alla webbläsare
Svar #3
Kontrollera domänens webbserver för http://www.example.com konfiguration för X-Frame-Options. Det är en säkerhetsfunktion som är utformad för att förhindra clickJacking-attacker.
Hur fungerar clickJacking?
- Den onda sidan ser exakt ut som offrets sida.
- Sedan lurade det användare att ange sitt användarnamn och lösenord.
Tekniskt sett har den onda en iframe med källan till offerets sida.
<html>
<iframe src='victim-domain.example'/>
<input id="username" type="text" style="display: none;"/>
<input id="password" type="text" style="display: none;"/>
<script>
//some JS code that click jacking the user username and input from inside the iframe...
<script/>
<html>
Hur säkerhetsfunktionen fungerar
Om du vill förhindra att webbserverförfrågningar renderas inom en iframe lägg till x-frame-options
X-Frame-Options NEJ
Alternativen är:
SAMEORIGIN: tillåt endast att min egen domän renderar min HTML inuti en iframe.DENY: tillåt inte att min HTML renderas inne i någon iframeALLOW-FROM https://example.com/: tillåt specifik domän att visa mitt HTML-innehåll inuti en iframe
Detta är ett exempel på IIS-konfiguration:
<httpProtocol>
<customHeaders>
<add name="X-Frame-Options" value="SAMEORIGIN" />
</customHeaders>
</httpProtocol>
Lösningen på frågan
Om webbservern aktiverade säkerhetsfunktionen kan det orsaka ett klient-sida SecurityError som det borde.
Svar #4
För mig ville jag implementera en tvåvägshandskakning, vilket betyder:
- föräldrafönstret kommer att laddas snabbare än iframe
- iframe ska kommunicera med föräldrafönstret så snart det är redo
- föräldern är redo att ta emot iframe-meddelandet och svara
denna kod används för att ställa in vit etikett i iframe med hjälp av [CSS anpassad egenskap]
kod:
iframe
$(function() {
window.onload = function() {
// create listener
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);
// call parent
parent.postMessage("GetWhiteLabel","*");
}
});
förälder
$(function() {
// create listener
var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
var eventer = window[eventMethod];
var messageEvent = eventMethod == "attachEvent" ? "onmessage" : "message";
eventer(messageEvent, function (e) {
// replay to child (iframe)
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);
});
naturligtvis kan du begränsa ursprungen och texten, detta är kod som är lätt att arbeta med
jag tyckte detta exempel var hjälpsamt:
[Cross-Domain Messaging With postMessage]
