SecurityError: Blocked a frame with origin from accessing a cross-origin frame

JavascriptJquerySecurityIframeSame Origin-Policy

Javascript Problem Overview


I am loading an <iframe> in my HTML page and trying to access the elements within it using Javascript, but when I try to execute my code, I get the following error:

SecurityError: Blocked a frame with origin "http://www.<domain>.com" from accessing a cross-origin frame.

Can you please help me to find a solution so that I can access the elements in the frame?

I am using this code for testing, but in vain:

$(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!";
    });
});

Javascript Solutions


Solution 1 - Javascript

Same-origin policy

You can't access an <iframe> with different origin using JavaScript, it would be a huge security flaw if you could do it. For the same-origin policy browsers block scripts trying to access a frame with a different origin.

Origin is considered different if at least one of the following parts of the address isn't maintained:

protocol://hostname:port/...

Protocol, hostname and port must be the same of your domain if you want to access a frame.

NOTE: Internet Explorer is known to not strictly follow this rule, see here for details.

Examples

Here's what would happen trying to access the following URLs from 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 

Workaround

Even though same-origin policy blocks scripts from accessing the content of sites with a different origin, if you own both the pages, you can work around this problem using window.postMessage and its relative message event to send messages between the two pages, like this:

  • In your main page:

    const frame = document.getElementById('your-frame-id');
    frame.contentWindow.postMessage(/*any variable or object here*/, 'http://your-second-site.com');
    

    The second argument to postMessage() can be '*' to indicate no preference about the origin of the destination. A target origin should always be provided when possible, to avoid disclosing the data you send to any other site.

  • In your <iframe> (contained in the main page):

    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; 
        } 
    }); 
    

This method can be applied in both directions, creating a listener in the main page too, and receiving responses from the frame. The same logic can also be implemented in pop-ups and basically any new window generated by the main page (e.g. using window.open()) as well, without any difference.

Disabling same-origin policy in your browser

There already are some good answers about this topic (I just found them googling), so, for the browsers where this is possible, I'll link the relative answer. However, please remember that disabling the same-origin policy will only affect your browser. Also, running a browser with same-origin security settings disabled grants any website access to cross-origin resources, so it's very unsafe and should NEVER be done if you do not know exactly what you are doing (e.g. development purposes).

Solution 2 - Javascript

Complementing Marco Bonelli's answer: the best current way of interacting between frames/iframes is using window.postMessage, supported by all browsers

Solution 3 - Javascript

Check the domain's web server for http://www.<domain>.com configuration for X-Frame-Options It is a security feature designed to prevent clickJacking attacks,

How Does clickJacking work?

  1. The evil page looks exactly like the victim page.
  2. Then it tricked users to enter their username and password.

Technically the evil has an iframe with the source to the victim page.

<html>
    <iframe src='victim_domain.com'/>
    <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>

How the security feature work

If you want to prevent web server request to be rendered within an iframe add the x-frame-options

> X-Frame-Options DENY

The options are:

  1. SAMEORIGIN //allow only to my own domain render my HTML inside an iframe.
  2. DENY //do not allow my HTML to be rendered inside any iframe
  3. "ALLOW-FROM https://example.com/" //allow specific domain to render my HTML inside an iframe

This is IIS config example:

   <httpProtocol>
       <customHeaders>
           <add name="X-Frame-Options" value="SAMEORIGIN" />
       </customHeaders>
   </httpProtocol>

The solution to the question

If the web server activated the security feature it may cause a client-side SecurityError as it should.

Solution 4 - Javascript

For me i wanted to implement a 2-way handshake, meaning:

  • the parent window will load faster then the iframe
  • the iframe should talk to the parent window as soon as its ready
  • the parent is ready to receive the iframe message and replay

this code is used to set white label in the iframe using [CSS custom property]
code:
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","*");
	}
});

parent

$(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);
});

naturally you can limit the origins and the text, this is easy-to-work-with code
i found this examlpe to be helpful:
[Cross-Domain Messaging With postMessage]

Solution 5 - Javascript

There is a workaround, actually, for specific scenarios.

If you have two processes running on the same domain but different ports, the two windows can interact without limitations. (i.e. localhost:3000 & localhost:2000). To make this work, each window needs to change their domain to the shared origin:

document.domain = 'localhost'

This also works in the scenario that you are working with different subdomains on the same second-level domain, i.e. you are on john.site.com trying to access peter.site.com or just site.com

document.domain = 'site.com'

By explicitily setting document.domain; the browser will ignore the hostname difference and the windows can be treated as coming from the 'same-origin'. Now, in a parent window, you can reach into the iframe: frame.contentWindow.document.body.classList.add('happyDev')

Solution 6 - Javascript

I would like to add Java Spring specific configuration that can effect on this.

In Web site or Gateway application there is a contentSecurityPolicy setting

in Spring you can find implementation of WebSecurityConfigurerAdapter sub class

contentSecurityPolicy("
script-src 'self' [URLDomain]/scripts ; 
style-src 'self' [URLDomain]/styles;
frame-src 'self' [URLDomain]/frameUrl...

...

.referrerPolicy(ReferrerPolicyHeaderWriter.ReferrerPolicy.STRICT_ORIGIN_WHEN_CROSS_ORIGIN)

Browser will be blocked if you have not define safe external contenet here.

Solution 7 - Javascript

If you have control over the content of the iframe - that is, if it is merely loaded in a cross-origin setup such as on Amazon Mechanical Turk - you can circumvent this problem with the <body onload='my_func(my_arg)'> attribute for the inner html.

For example, for the inner html, use the this html parameter (yes - this is defined and it refers to the parent window of the inner body element):

<body onload='changeForm(this)'>

In the inner html :

    function changeForm(window) {
        console.log('inner window loaded: do whatever you want with the inner html');
        window.document.getElementById('mturk_form').style.display = 'none';
    </script>

Solution 8 - Javascript

I experienced this error when trying to embed an iframe and then opening the site with Brave. The error went away when I changed to "Shields Down" for the site in question. Obviously, this is not a full solution, since anyone else visiting the site with Brave will run into the same issue. To actually resolve it I would need to do one of the other things listed on this page. But at least I now know where the problem lies.

Solution 9 - Javascript

  • Open the start menu
  • Type windows+R or open "Run
  • Execute the following command.

chrome.exe --user-data-dir="C://Chrome dev session" --disable-web-security

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionmubashermubiView Question on Stackoverflow
Solution 1 - JavascriptMarco BonelliView Answer on Stackoverflow
Solution 2 - JavascriptGeertView Answer on Stackoverflow
Solution 3 - JavascriptShahar ShokraniView Answer on Stackoverflow
Solution 4 - JavascriptYakir ManorView Answer on Stackoverflow
Solution 5 - Javascriptnikk wongView Answer on Stackoverflow
Solution 6 - JavascriptsspView Answer on Stackoverflow
Solution 7 - JavascriptZhanwen ChenView Answer on Stackoverflow
Solution 8 - JavascriptNick K9View Answer on Stackoverflow
Solution 9 - Javascriptsakthi sudhanView Answer on Stackoverflow