How to postmessage HTMLIFrameElement? - javascript

I'm having issue passing HTMLIFrameElement object from parent site to iframe (located on a different domain) using postMessage method.
This is my code that I already tried:
var frame = document.getElementById('myHTMLIFrameElement');
frame = JSON.parse(JSON.stringify(frame));
event.source.postMessage(frame, "*");
Unfortunately, JSON.parse/JSON.stringify does not seem to be the right way of handling HTMLIFrameElement object. Can you please advise how to pass through HTMLIFrameElement object correctly?

Parsing DOM elements as JSON does not do anything useful as far as I know.
Since postMessage() is part of the window object, you could try using the window object of the frame, which is found under the contentWindow property of the iframe.
So you could try something like:
var frame = document.getElementById('myHTMLIFrameElement');
frame.contentWindow.postMessage( "stuffYouWantToSendToTheIframe", '*' );
And then in the script inside the iframe:
window.addEventListener('message', function( event ) {
// handle message
});

Related

Access an Iframe variable from parent window

I have a webpage at url https://parent.com and it has an iframe injected into it with source https://iframe.com. Iframe has a global variable defined called iframe_variable. I want to access the iframe_variable from parent document.
I know browsers don't allow cross origin communication and they provide a postMessage API to do it securely.
Constraint: I do not have access to any of parent or iframe code.
On Browser console, I somehow want to access iframe_variable
I have tried the following:
Get reference of iframe first.
var iframe = document.getElementsByTagName('iframe')[0]; // There is only one iframe on document
Create a listener for message event posted from parent window.
var iframeListener = function(e) {
console.log("Got message from parent");
e.source.postMessage(JSON.stringify({'IFRAME_VARIABLE': window.IFRAME_VARIABLE}));
}
Create a listener for parent window to accept 'message' posted from iframe.
parentListener = function(e) {
console.log('Got message from iframe');
var data = JSON.parse(e.data);
window.VARIABLE = data.IFRAME_VARIABLE;
}
Attach parent_listener to message event.
window.addEventListener('message', parentListener, false);
Now if i try to post a message to iframe from parent as follows:
iframe.contentWindow.postMessage('test message', '*')
It doesn't trigger 'iframeListener'. The reason is because it is not registered against the message event in iframe.
I don't think I can even do that from the browser console when I am on parent.com as any attempt to do iframe.contentWindow.addEventListener will result in an error as it will be an attempt to access a different domain.
Is there a workaround that? Is there anything that I am missing in my understanding and research.
P.S: I have not written the origin checks for simplicity. I know I must check for the origin a message is posted from. Not doing that leaves a huge security hole.

Is there a way to prevent an iframe sandbox from sending postMessages?

Let's say I have an Iframe with the attribute sandbox="allow-scripts".
I might or might not be in control of the page loading that iframe.
Is there any possibility how to prevent the iframe from sending postMessages other than overwriting the parents postMessage function - which I might not be able to do if the parent is not my domain.
A colleague came up with an idea. One can sum it up with: make the parent part of your domain so that you can overwrite its postMessage method.
If it is not possible to control the top window containing the iframe, why not put the original iframe within another iframe. The additional frame-layer can act as a firewall. By overwriting the postMessage-Method of that intermediate firewall-iframe one can make sure that the original iframe can postMessage whatever it wants but the firewall-iframe only forwards incomming messages that are wished to be postable.
Of course this comes with some constraints as to what has to be the destination domain of the postMessage-call.
You should probably just check the read-only source property of the MessageEvent.
<iframe src="evil.html" class="ignore-messages"></iframe>
<iframe src="safe.html"></iframe>
window.addEventListener('message', function(e)
{
// Blacklist messages if e.source matches iframe.ignore-messages
if(Array.from(document.querySelector('iframe.ignore-messages'))
.map(f => f.contentWindow)
.indexOf(e.source) !== -1
) return;
// handle message from safe.html
// this message cannot come from evil.html,
// since that iframe has the class "ignore-messages"
};
Other ways to achieve this are through a whitelist such as:
// allow only from parent
if(e.source !== parent) return;
// allow only from a given set of iframes
if(Array.from(document.querySelectorAll('iframe.accept-messages')).map(f => f.contentWindow).indexOf(e.source) === -1) return;
The advantage of a whitelist over a blacklist, is that the iframe which sent a message may not be in the DOM-tree anymore, or the classList may have been changed, etc. Which is more common when working with dynamic HTML generated by javascript. Therefore, using a whitelist is a foolproof approach.

Send a message from an iframe on the main page

I have seen from this documentation: https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage , the way to pass a data correctly to an iframe. But now I want to send an answer:
//from main page
myIframe.contentWindow.postMessage('send me a response', '*');
//from iframe of main page
window.addEventListener("message", receiveMessage, false);
function receiveMessage(event){
alert(event.data);//the value of message
//now i need to send an answer 'this is a response'
}
}
How do I send an answer to the main page from the iframe?
I need really of this answer.
Edit:
Ok i found the solution ty at all.
You have access to the parent window on the global window.parent.
I believe it is as easy as using this object's method at this point to postMessage. So something like:
var parent = window.parent;
parent.postMessage("some message");
A full example can be found here.
The gist is the window.parent.postMessage() function takes the following arguments: otherWindow.postMessage(message, targetOrigin, [transfer]);
I would consider using easyXDM
EasyXDM WebSite

Issue communication with postMessage from parent to child iFrame

I'm having an issue communicating from my parent window to the child iFrame. But in the other side, everything works perfectly.
Here is how I get the chil iFrame object in order to fire the postMessage function:
var iFrame = document.getElementById('Frame').contentWindow;
When I print it int he console, I get the following:
Window {parent: Window, opener: null, top: Window, length: 0, frames: Window…}
When I proceed to the postMessage function as follows:
iFrame.postMessage("message", "http://contoso.com");
It shows me an error when loading the page: iFrame.postMessage is not a function.
When I execute the postMessage in console, I get an undefined
What am I doing wrong ?
try this
var iFrame = document.getElementById('Frame');
iFrame.contentWindow.postMessage("message", "http://contoso.com");
I had this problem too. I found solution from this website https://www.viget.com/articles/using-javascript-postmessage-to-talk-to-iframes
I wasn't able to get this working using a querySelector approach.
What worked for me was the following. I'll refer to the two webpages as the parent that has an iframe on it and the src as the page inside the iframe.
On the src page, I post a message, with the parent url as the origin:
// src
window.parent.postMessage({
type: "connect",
url: window.location.href
}, "http://iframeparent.dev", );
Then in the parent page, I listen for this. It will have a property called source which is the iframe in question. This property can be posted to.
// parent
window.addEventListener("message", (event) => {
// this is the magic connection:
event.source;
}, false);
So you could do something like:
// parent
let sources = [];
window.addEventListener("message", (event) => {
sources.push(event.source);
}, false);
function something() {
sources.forEach(source => {
source.postMessage({some: "data"}, "http://iframesrc.dev")
})
}
Below code also works.
$('#id')[0].contentWindow.postMessage("hello world",targetOrigin);
There is a difference between jQuery selector and document.getElementById.
Document.getElementByID returns HTML DOM object.
jQuery selector returns jQuery object.
For more information please find below link.
document.getElementById vs jQuery $()

postMessage() generates error "undefined is not a function"

I'm trying to get postMessage() to work to communicate between an iframe and my main website. However using the exact syntax given in the example code on MDN, I am being presented with a nice Undefined is not a function error. I've tried several things, such as initializing the iframe inside Javascript and appending it to my page, but that left me with the same error. Same for have seperate selectors to select my iframe.
I have the following Javascript code:
<script type="text/javascript">
$(document).ready(function() {
$('.editor').postMessage("A", "domain here");
});
function receiveMessage(event)
{
if (event.origin !== "domain here")
return;
// Do something
}
window.addEventListener("message", receiveMessage, false);
</script>
The script above tries to send a message to my iframe on the page, which looks like:
<iframe src="domain here/frameListener.html" class="editor"></iframe>
It then has a function receiveMessage to catch any messages being send as a response to the main webpage. Last but not least, I've tried the answers given in this question: But that did not fix my problem. It is therefore not a duplicate.
How can I get rid of this error message?
postMessage is not a jQuery function so you need to get the actual window DOM element and call it on that:
$('.editor').get(0).contentWindow.postMessage("A", "domain here");
Furthermore, you need to access the contentWindow property of the iframe. Here is an excerpt from the MDN docs:
otherWindow.postMessage(message, targetOrigin, [transfer]);
otherWindow
A reference to another window; such a reference may be
obtained, for example, using the contentWindow property of an iframe
element, the object returned by window.open, or by named or numeric
index on window.frames.

Categories

Resources