Polityka tego samego pochodzenia
Nie możesz uzyskać dostępu do <iframe>
innego pochodzenia za pomocą JavaScript, byłoby to ogromną wadą bezpieczeństwa, gdybyś mógł to zrobić. W przypadku przeglądarek zasad tego samego pochodzenia skrypty blokują próby uzyskania dostępu do ramki o innym pochodzeniu .
Pochodzenie uważa się za różne, jeśli nie zachowano co najmniej jednej z następujących części adresu:
<protocol>://<hostname>:<port>/...
Protokół , nazwa hosta i port muszą być takie same jak w domenie, jeśli chcesz uzyskać dostęp do ramki.
UWAGA: wiadomo, że Internet Explorer nie ściśle przestrzega tej zasady, zobacz tutaj, aby uzyskać szczegółowe informacje.
Przykłady
Oto, co by się stało, próbując uzyskać dostęp do następujących adresów URL z 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
Obejście
Mimo że zasady tego samego pochodzenia blokują skryptom dostęp do zawartości witryn o innym pochodzeniu, jeśli jesteś właścicielem obu stron, możesz obejść ten problem, używając window.postMessage
i jego względnego message
zdarzenia do wysyłania wiadomości między dwiema stronami, w następujący sposób:
Na twojej stronie głównej:
let frame = document.getElementById('your-frame-id');
frame.contentWindow.postMessage(/*any variable or object here*/, 'http://your-second-site.com');
Drugim argumentem postMessage()
może być '*'
wskazanie braku preferencji co do pochodzenia miejsca docelowego. W miarę możliwości zawsze należy podać miejsce docelowe, aby uniknąć ujawnienia danych wysyłanych do innych witryn.
W twoim <iframe>
(zawartym na stronie głównej):
window.addEventListener('message', event => {
// IMPORTANT: check the origin of the data!
if (event.origin.startsWith('http://your-first-site.com')) {
// 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;
}
});
Metodę tę można zastosować w obu kierunkach , tworząc odbiornik również na stronie głównej i odbierając odpowiedzi z ramki. Ta sama logika może być również zaimplementowana w wyskakujących oknach i zasadniczo w każdym nowym oknie generowanym również przez stronę główną (np. Przy użyciu window.open()
), bez różnicy.
Wyłączenie polityki tego samego pochodzenia w Twojej przeglądarce
Jest już kilka dobrych odpowiedzi na ten temat (właśnie znalazłem googlujących się w Google), więc dla przeglądarek, w których jest to możliwe, połączę odpowiedź względną. Pamiętaj jednak, że wyłączenie zasad tego samego pochodzenia wpłynie tylko na Twoją przeglądarkę . Ponadto uruchomienie przeglądarki z wyłączonymi ustawieniami zabezpieczeń tego samego pochodzenia zapewnia każdemu dostęp do strony internetowej do zasobów pochodzących z różnych źródeł, więc jest to bardzo niebezpieczne i NIGDY nie powinno być wykonywane, jeśli nie wiesz dokładnie, co robisz (np. W celach programistycznych) .
Access-Control-Allow-Origin
nie dotyczy iFrames, tylko XHR, czcionek, WebGL icanvas.drawImage
. Wierzę, żepostMessage
to jedyna opcja.iframe.src
, a jeśli witryna różni się od nazwy hosta Twojej domeny, nie możesz uzyskać dostępu do tej ramki.~
zwraca uzupełnienie liczby 2, więcn
staje się-n-1
, co oznacza, że tylko-1
się stanie0
(co jest interpretowane jakofalse
), a każda inna wartość przejdzie test. IE0 = -(-1)-1
nie-(-1+1)
.location.ancestorOrigins[0]
to lokalizacja ramki nadrzędnej. Jeśli twoja ramka działa w innej witrynie i sprawdzasz za pomocąevent.origin.indexOf(location.ancestorOrigins[0])
, sprawdzasz, czy początek zdarzenia zawiera adres ramki nadrzędnej, co zawsze będzietrue
, dlatego zezwalasz każdemu rodzicowi o dowolnym pochodzeniu na dostęp do ramki, a to oczywiście nie jest czymś, co chcesz zrobić. Co więcej,document.referrer
jest to również zła praktyka, jak już wyjaśniłem w komentarzach powyżej.Uzupełnienie odpowiedzi Marco Bonellego: najlepszy obecny sposób interakcji między ramkami / ramkami iframe
window.postMessage
, obsługiwany przez wszystkie przeglądarkiźródło
window.postMessage
działa, powielałoby tylko zaakceptowaną odpowiedź, do której już się odwołuję. Ponadto podstawową wartością dodaną przez moją odpowiedź jest właśnie odwołanie się do dokumentacji zewnętrznej.Sprawdź, czy na serwerze internetowym domeny znajduje się
http://www.<domain>.com
konfiguracja.X-Frame-Options
Jest to funkcja bezpieczeństwa zaprojektowana w celu zapobiegania atakom typu ClickJacking,Jak działa ClickJacking?
Technicznie rzecz biorąc, zło ma
iframe
źródło strony ofiary.Jak działa funkcja bezpieczeństwa
Jeśli chcesz uniemożliwić renderowanie żądania serwera WWW w ramach
iframe
dodania opcji ramki-xDostępne są następujące opcje:
Oto przykład konfiguracji IIS:
Rozwiązanie pytania
Jeśli serwer WWW aktywuje funkcję bezpieczeństwa, może spowodować błąd SecurityError po stronie klienta, tak jak powinien.
źródło
Dla mnie chciałem wdrożyć dwukierunkowy uścisk dłoni, co oznacza:
- okno nadrzędne ładuje się szybciej niż ramka iframe
- ramka iframe powinna mówić do okna nadrzędnego, gdy tylko będzie gotowe
- rodzic jest gotowy na otrzymanie komunikatu iframe i odtworzenie
ten kod służy do ustawiania białej etykiety w ramce iframe za pomocą [niestandardowej właściwości CSS]
:
iframe
rodzic
oczywiście możesz ograniczyć pochodzenie i tekst, jest to łatwy do pracy z kodem.
Ten przykład był pomocny:
[Wiadomości między domenami z postMessage]
źródło
Chciałbym dodać konfigurację specyficzną dla Java Spring, która może mieć na to wpływ.
W witrynie sieci Web lub aplikacji Gateway istnieje ustawienie contentSecurityPolicy
wiosną można znaleźć implementację podklasy WebSecurityConfigurerAdapter
...
Przeglądarka zostanie zablokowana, jeśli nie zdefiniujesz tutaj bezpiecznego zewnętrznego konta.
źródło
Jeśli masz kontrolę nad zawartością elementu iframe - to znaczy, jeśli jest on tylko ładowany w konfiguracji krzyżowej, takiej jak w Amazon Mechanical Turk - możesz obejść ten problem za pomocą
<body onload='my_func(my_arg)'>
atrybutu wewnętrznego HTML.Na przykład dla wewnętrznego html użyj
this
parametru html (tak -this
jest zdefiniowane i odnosi się do okna nadrzędnego wewnętrznego elementu ciała):<body onload='changeForm(this)'>
W wewnętrznym html:
źródło
chrome.exe --user-data-dir="C://Chrome dev session" --disable-web-security
źródło