My goal is to add css to the iframe content from the parent page. I have two different domains one rendering an iframe from the other, I'm using postMessage to bypass the same-origin policy issue however this doesn't seem to work as expected. When I try to console.log(iframe.contentWindow) I get an error in the console Uncaught DOMException: Blocked a frame with origin "http://parent.domain.com" from accessing a cross-origin frame.
iframe
<iframe
sandbox="allow-same-origin allow-scripts allow-popups allow-forms"
src="https://domain.with.iframe.content"
width="100%"
frameBorder="0"
id="iframe-1"
></iframe>
Page with iframe.
<script>
window.addEventListener('message', function(e) {
var iframe = document.getElementById("iframe-1");
console.log(e)
console.log(e.origin)
console.log(iframe)
console.log(iframe.contentWindow)
}, false);
</script>
Page that I'm iframing.
<script>
var body = document.body
body.onload = function resize() {
parent.postMessage(["hey"], "*");
}
</script>
</script>
From the console I can see that the message event listener is running, however this line console.log(iframe.contentWindow) throws the error. Any help will be much appreciated, thank you.
Adding an answer from my comments:
You can't access iframe.contentWindow from the parent frame, see SecurityError: Blocked a frame with origin from accessing a cross-origin frame
So you'll need to pass the CSS you need back and forth with postMessage.
Depending on how you get the CSS but assuming you have it as a string, you could send that string to the iframe using postMessage. Inside the iframe you could create a style tag, set the innerHTML of that tag to the CSS string and append it to the document head. Like in this article under Global Styles https://dev.to/karataev/set-css-styles-with-javascript-3nl5
Related
I have 2 vhosts setup with different subdomains; x.domain.com and y.domain.com. I'm rendering iframes from x in y. So issues rendering and displaying the iframe but getting cannot access the iframe contents. I have no headers set at the moment and tried to solve it with csp but couldn't get around the error.
x.domain.com/frame.html:
<html>
<body>
</body>
<script>
function myFunc() {
console.log('called');
}
</script>
</html>
y.domain.com:
let iframe = (iframe_element.contentWindow || iframe_element.contentDocument);
if (iframe.document) iframe = iframe.document;
iframe.myFunc();
postMessage is not option as I can't modify iframe contents.
I need to display an input from user that is html, I don't want user to be able to use script here so i'm using the sandbox mode of iframe to have content without script.
<iframe class="frame"
srcdoc="<h1>title</h1><p>content1</p><p>content2</p>"
sandbox=""
style="width:100%;border:none;overflow:hidden;">
</iframe>
The problem is that I would like to be able to resize this frame to match the height of it's content with the bellow function but I can't access to iFrame.contentWindow.document due to cross-origin.
function resizeIFrameToFitContent( iFrame ) {
iFrame.width = iFrame.contentWindow.document.body.scrollWidth;
iFrame.height = iFrame.contentWindow.document.body.scrollHeight;
}
Is there a way to solve this ?
Finally I solved the issue. The problem was coming from the sandbox mode that is restricting everything so I needed to allow the javascript from same origin to be able to access it from my page :
<iframe class="frame"
srcdoc="<h1>title</h1><p>content1</p><p>content2</p>"
sandbox="allow-same-origin"
style="width:100%;border:none;overflow:hidden;">
</iframe>
I wish to reference this iframe:
<iframe id= "bro" src="http://www.youtube.com" style="visibility:hidden;display:none"></iframe>
Instead of getBackgroundPage() in the following code:
img.src = chrome.extension.getBackgroundPage().imageSrc[0];
I've tried:
img.src = document.getByElementId("bro").imageSrc[0];
That failed hard. Any suggestions?
First of all,
document.getByElementId("bro")
will return an iframe object, and it doesn't have property called imageSrc.
With that, assuming you have the iframe object, you will then have to deal with Cross Domain Policy that will prevent you from accessing the content of the iframe.
I'm trying to make the following work in Chrome: http://jsfiddle.net/3es621uz/1/
HTML:
<iframe src="about:blank" id="iframe" sandbox="allow-same-origin"></iframe>
Javascript:
var b, i;
i = document.getElementById('iframe');
b = i.contentDocument.createElement('button');
b.innerHTML = 'Click me!';
b.addEventListener('click', function() {
return alert('Used to work!');
});
i.contentDocument.body.appendChild(b);
Clicking the button used to show the alert in Chrome at some point. It still does in Firefox but doesn't work in Safari. Is there any way for me to bind events in the iframe from outside without allowing scripts inside it to execute?
Related document: https://github.com/mdn/browser-compat-data/pull/7153, and I found that Chrome had changed its behaviour since version 71.
The same problem should happen when trying to post messages:
iframe.contentWindow.addEventListener('message', console.log);
iframe.contentWindow.postMessage('what', '*');
// => throw "Blocked script execution in 'about:blank' because the document's frame is sandboxed and the 'allow-scripts' permission is not set"
// but it worked after Chrome 71
MDN mentions:
When the embedded document has the same origin as the main page, it is strongly discouraged to use both allow-scripts and allow-same-origin at the same time, as that allows the embedded document to programmatically remove the sandbox attribute. Although it is accepted, this case is no more secure than not using the sandbox attribute.
You can't both include arbitrary (untrusted) content and programmatically control the frame using sandbox.
We have two domains, domain.com and sub.domain.com
On domain.com
<html>
<head>
<title>Main</title>
</head>
<body>
<h1>This is the parent</h2>
<iframe src="http://sub.domain.com/results.aspx"
width="100%" height="1px" id="iframe1">
</iframe>
</body>
</html>
Quesiton: How can we adjust the iframe height from 1px to it's real height (when the iframe loads)? As the user plays in the iframe, it's height can change, so I suspect it might be needed to hook it to some event.
Now I'm fully aware that cross scripting is prevented in the browser and that even subdomains (or different port numbers) constitute "cross-domain". However, we control both the domains so I'm looking for a good solution for this. We looked at window.postMessage which seems to be designed specifically for this but couldn't make it work.
Your case is simple because it's cross-scripting subdomains (not cross-scripting different domains). Just assign document.domain = "domain.com" in both your page and iframe.
For more information, check out:
Cross sub domain iframes and JavaScript and
How to communicate between frames?
What you're looking for is iframe message passing:
https://developer.mozilla.org/en-US/docs/Web/API/window.postMessage
In the parent page:
var iframe = document.getElementById('myIframe');
function resizeIframe(event){
if (event.origin !== "http://example.org"){
// We trust this message
iframe.setAttribute("style", "width:" + event.data + "px;");
}
}
window.addEventListener('message', resizeIframe, false);
In the child page:
function postParent(){
window.postMessage($(body).height(), 'http://parentdomain.org');
}
$(window).on('load', postParent);