Eroare: Permisiune refuzată pentru accesarea proprietății „document” (Programare, Javascript, Html, Iframe, Xss, Controlul Accesului)

sbrm1 a intrebat.

Am un document HTML care conține un element iframe. De fiecare dată când încerc să accesez sau să modific acest iframe cu JS, primesc Error: Permission denied to access property "document".

Eu folosesc frame.contentWindow.document.body.innerHTML sau frame.contentWindow.document.body.onload sau atribute similare pentru a accesa sau modifica iframe. (În codul dat, se utilizează iframe este denumit frame.)

Pentru aplicația web pe care o dezvolt, accesul la aceste atribute este necesar și nu mă pot lipsi de acestea (sau de alternative similare).

3 răspunsuri
Gihan Gamage

Puteți ocoli această problemă cu ajutorul YQL chiar dacă nu aveți acces la partea de antet a ferestrei de recepție. Cu metoda Postmessage, de asemenea, trebuie să editați scriptul ferestrei destinatarului. Dar folosind această metodă puteți încărca orice iframe fără să atingeți scripturile lor. Verificați acest lucru!

<html>
<iframe src="https://google.com/" width="500" height="300"></iframe>

<script>
var iframe = document.getElementsByTagName('iframe')[0];
var url = iframe.src;
var getData = function (data) {
    if (data && data.query && data.query.results && data.query.results.resources && data.query.results.resources.content && data.query.results.resources.status == 200) loadHTML(data.query.results.resources.content);
    else if (data && data.error && data.error.description) loadHTML(data.error.description);
    else loadHTML('Error: Cannot load ' + url);
};
var loadURL = function (src) {
    url = src;
    var script = document.createElement('script');
    script.src = 'https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20data.headers%20where%20url%3D%22' + encodeURIComponent(url) + '%22&format=json&diagnostics=true&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys&callback=getData';
    document.body.appendChild(script);
};
var loadHTML = function (html) {
    iframe.src = 'about:blank';
    iframe.contentWindow.document.open();
    iframe.contentWindow.document.write(html.replace(/<head>/i, '<head><base href="' + url + '"><scr' + 'ipt>document.addEventListener("click", function(e) { if(e.target && e.target.nodeName == "A") { e.preventDefault(); parent.loadURL(e.target.href); } });</scr' + 'ipt>'));
    iframe.contentWindow.document.close();
}

loadURL(iframe.src);
</script>
</html>

Comentarii

  • Sunt impresionat de acest bypass. Cu siguranță este ceva ce ar trebui folosit atunci când se demonstrează vulnerabilitățile Cross Frame Scripting. –  > Por Aday.
  • Da, evident! partea asta este gestionată de API-urile yahoo 🙂 –  > Por Gihan Gamage.
  • Dar nu pot folosi această metodă iframe.contentWindow.document.body.scrollHeight folosind răspunsul de mai sus. Puteți să mă ajutați pls? –  > Por Ranganathan.
  • Din ianuarie ’19, Yahoo a întrerupt yql. Este posibil să fie nevoie să utilizați o alternativă acum. –  > Por Sagar Solanki.
  • @Sagar Solanki Ce alternative pot fi folosite? –  > Por Filip Š.
sbrm1

Accesarea și apoi modificarea paginilor web în iframeale altor site-uri web este cunoscută sub numele de scripting între site-uri sau XSS și este o tehnică folosită de hackerii rău intenționați pentru a profita de victimele neștiutoare.

Producătorii de browsere au implementat o politică denumită „Same-Origin Policy” pentru a preveni un astfel de comportament și executarea arbitrară a codului JS.

Această eroare poate fi prevenită prin găzduirea documentului părinte și a documentului din iframe în același domeniu și subdomeniu și asigurându-vă că documentele sunt încărcate folosind același protocol.

Exemple de pagini incompatibile:

  1. http://www.example.org & http://www.example2.com
  2. http://abc.example.org & http://xyz.example.com
  3. http://www.example.org & https://www.example.com

Partajarea resurselor între origini este o soluție la această problemă.

De exemplu:
Dacă http://www.example.com ar dori să partajeze http://www.example.com/hello cu http://www.example.org, se poate trimite împreună cu documentul un antet care să arate astfel:

Access-Control-Allow-Origin: http://www.example.org

Pentru a-l trimite cu HTML, trebuie doar să îl puneți într-un fișier <META HTTP-EQUIV="..."> tag, astfel:

<head>
    ...
    <META HTTP-EQUIV="Access-Control-Allow-Origin" CONTENT="http://www.example.org">
    ...
</head>

Comentarii

  • Ce se întâmplă dacă nu am acces la partea „head” a paginii? Încerc să încorporez un widget în Squarespace. –  > Por PJ Brunet.
  • @PJBrunet Din păcate, nu aveți noroc… S-ar putea să vă pot ajuta dacă dați detalii despre widget și ce încercați să modificați. –  > Por sbrm1.
  • Aș prefera să nu vorbesc aici pe chat, ceea ce StackOverflow nu vede cu ochi buni. Squarespace permite într-adevăr accesul la „head” însă soluția ta nu m-a ajutat pentru că sunt pe un alt domeniu. Am ajuns să îmi rezolv problema schimbând URL-ul iframe-ului după un eveniment, iar apoi noul URL al iframe-ului a inclus parametrii mei, cum ar fi zipcode=12345 –  > Por PJ Brunet.
  • S-ar putea să mă înșel, dar poate doriți să testați aceste exemple. Cred că soluția ta funcționează doar pentru subdomenii și altele asemenea. Nu cred că controlul accesului funcționează între .org și .com (de exemplu, Bitcoin.com este adversarul lui Bitcoin.org), dar nu lucrez des cu iframe-uri, așa că nu sunt sigur. –  > Por PJ Brunet.
  • @PJJBrunet Mă voi uita în ea. –  > Por sbrm1.
joyBlanks

Puteți folosi postMessage

Fereastra 1 – primirea

window.addEventListener("message", receiveMessage, false);

function receiveMessage(event)
{
  var origin = event.origin || event.originalEvent.origin; 
  // For Chrome, the origin property is in the event.originalEvent object.
  if (origin !== "http://example.org:8080")
    return;

  // ...
}

Fereastra 2 – Transmitere

var popup = window.open(...popup details...);
popup.postMessage(
       "The user is 'bob' and the password is 'secret'", 
       "https://secure.example.net"
);

Trebuie să creați o altă pereche pentru a intercomunica.