I have a situation where I have an iframe hosting a third-party site. I need to pick up only that the iframe has navigated to its final "success" url, so I can respond.
However, as you may know, modern browsers prevent you from accessing the iframe document object, even the location, because of CORS security issues.
Right now, I am running a counter in the onload event of the iframe, and performing my response when the counter hits a certain number.
But this is very hacky and won't be reliable enough for a new situation where I am having to use this mechanism.
So I'm looking for some wizard to tell me a better way. I just need to know when it's reached a certain URL.
BTW jquery is not an option; this is an Angular2 app.
Thanks!
frood
If you control both parent and embedded websites (And don't have to support very old browsers) I would consider using the postMessage API. It enables simple event communication between the parent and the child.
Here is a nice simple example - link
Related
In our web app/site, I need to use an iframe or a popup window to validate if the current token is valid and refresh it if no.
So, I create an iframe, and set the property 'src' to the validation link such as "https://<domain_name>/auth?client_id=xxx" which is different to our app domain https://<app_domain>. and the return value will like "https://<domain_name>/code=yyyy"
document.createElement('iframe');
and I added the message handle for the web app/site, like
window.addEventListener("message", this.messageHandler);
in the messageHandler, I will check if the message is from a specified website, and then validate the "code" value, blabla, etc.
But when running in Chrome, I always got the error
"Blocked autofocusing on a element in a cross-origin subframe."
what confused me is:
it always failed when running in the Chrome browser, but it can work fine in Firefox and Edge chromium.
I tried to set iframe.sandbox = "allow-forms allow-scripts allow-same-origin", the problem still existed.
If the validating token failed in iframe or timeout, I will create a popup window to continue validating and refresh the token. But every time, using popup window can always succeed. If it is really a cross-origin issue, why using iframe failed but using popup window succeeded.
I didn't use window.postmessage. because I don't know how to pass the return value of iframe/popup-window to the main page.
I used CORS extension of Chrome or using parameter --disable-web-security when launching Chrome. the problem still existed.
when I created the iframe or popup window. it is very simple, I just set the iframe.src property, there is no element being created.
any help will be much appreciated.
p.s.
I refer to the following doc:
Blocked autofocusing on a form control in a cross-origin subframe
https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy
https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage
Support for iframes in web development will only get worse over time as they are a security black hole, browsers are gradually over time locking out features and use of them.
I am assuming you are doing this because you are validating a user on a third party service, validating by watching the response of a third party service website?
Without knowing the service you are using I cannot comment specifically but for anyone looking to do something similar I would highly suggest not doing this:
As mentioned, iframes are constantly having features locked down due to security concerns
An attacker could change the source of the iframe and submit their own iframe to look like it has been correctly validated
It's unlikely that the page you are using as your iframe src is intended for this use, which will come back and bite you when the 3rd party developer changes how their page behaves, which they likely will do without knowing it's going to break your application
I recommend:
Finding a stable API the 3rd party service offers and using that
Finding another service if none exist
Apologies to rain on your parade!
I disagree that iframes are a security risk, rather they can be if not implemented properly.
How to implement them properly should be asked in another question and probably starting with a carefully implemented Content Security Policy as a priority.
I also use iframes within a Chrome extension that has to pass rigorous Google security.
As for the question, I've noticed that error too and I am focusing on an input box when the iframe is loaded and the focus works! I put it down to being a Chrome bug as the warning suggests it has stopped auto focusing when it hasn't.
As for the un-related point about passing the value back to the parent holding the iframe, I can help you with that, but you should ask it in a new question.
Disable some feature of browser setting
Browser Changes
chrome://flags/#cookies-without-same-site-must-be-secure
chrome://flags/#same-site-by-default-cookies
chrome://flags/#enable-removing-all-third-party-cookies
Above URL just paste it and disabled it. Then ok and relaunch the browser.
Then done it.
I want to redirect my website from iframe to main url, here is my code:
window.setTimeout(function() {
window.top.location = jQuery("link[rel=canonical]").attr("href") + "#ref=shahrekhabar";
return false;
}, 100);
It works on Firefox but Google Chrome blocked this type of redirecttion.
I try with window.top.location.href and window.top.location.replace and window.top.location.assign but no luck.
The reason:
Some spam sites shows my site in iframe and I want to escape from them and I think redirection is good solution.
Edit to answer the TRUE question:
A common issue with stack overflow is that users will often ask how to do something they think solves the problem they are encountering, rather than just asking us how to solve the problem. We always appreciate hearing how you've gone about trying to solve your problem, but it's always best if we know that and what the root problem is. So in your case, given your comment on my answer, the question should have been:
Currently my website is being shown in iframes on sites that I have no control over? I'd like to prevent them from doing this, how can I do so? I'm currently trying to redirect my website from iframe to main url, but it won't work on Chrome. ... Rest of question ...
Given this question, my original answer is useless as:
You still can't and shouldn't be able to alter the URL of the parent window.
You don't own the sites showing your page in the iframe, which means you can't register a listener to handle the postMessage or CustomEvent.
Funny enough, what you're trying to do is the exact reason why chrome doesn't let you do it hahaha. But don't worry there is still a solution.
Introducing CORS!
CORS or Cross Origin Resource Sharing is the name for when a site on one domain accesses resources that aren't on the same domain. Doesn't matter who owns either site, if the two domains are different it's CORS. Now this is good for you because there are such things as CORS policies where you can prevent anyone from even accessing a resource on your domain if they make a CORS request. Keep in mind this will mean you can't display your site within an iframe on another one of your sites unless they're on the same domain, but it sounds like it may be worth it for you.
In case you're curious, unlike what you're trying to do, using CORS policy is very much standard procedure for developers that don't wish for their sites to appear in iframes and is in fact used by famous sites such as facebook, google, and even good ole stackoverflow (I would know, I tried to make a way to view multiple questions at the same time via iframes a while back). I've included an example below that shows this all to be true, alongside an example of a site that doesn't care (editpad.org). In order to implement this on your site check out this link.
<iframe src="https://www.editpad.org/"> </iframe>
<iframe src="https://www.google.com/"> </iframe>
<iframe src="https://www.facebook.com/"> </iframe>
<iframe src="https://stackoverflow.com/posts/53917955"> </iframe>
The old answer:
So you're trying to change the location of the parent window from an iframe? This sounds extremely dangerous and the fact that Firefox doesn't block it worries me. Good job Chrome!
Why wouldn't you want this?
I can think of a few reasons you wouldn't want this, but the biggest is that it's just poor programming. A page should work completely independent of whether or not it is inside an iframe, and even if the page should only be viewed in an iframe it still shouldn't be interacting with the parent window in such a direct way.
Possible issues that could arise if this were allowed on all platforms:
Include an iframe in your ads and as soon as your ad is displayed, redirect the user to your site or worse, redirect them to a mirror of the current site that you're hosting to collect passwords / personal information.
If you can mess with the windows location (arguably the most important and static thing about a web page being viewed) why can't you mess with anything? Can you go into the parent window and adjust the DOM or do a query selection for inputs of type password in order to copy the values? Or what about attaching event listeners to the parent window silently such that you can log any and all key presses.
How can you work around it?
Don't worry too much about the issues I brought up above, as they can all be avoided by following proper standards. In fact, the JavaScript devs envisioned this exact problem which is why you can post messages across windows. Look into this link and go from there, feel free to comment if you have any questions but it should be as simple as posting a message, detecting it on the parent window, and then changing the location as you wish.
If you need to send data from the iframe to the parent window, or your iframe isn't hosted on the same domain, you can instead use CustomEvents (which I prefer even when my iframe is on the same domain) which allow you to attach a data object.
As for why either of these two solutions is better than directly manipulating the parent window, it's all due to the parent window needing to register a listener for the message / custom event. If your page is not inside an iframe it'll simply post a message to itself which it won't be listening for. If your page is inside an iframe on the page it should be on, your parent page should already have registered the proper listeners. And there is no chance for malicious use of these features because again, I have to register a listener and I choose what is done with the event once it's caught.
I'm trying to create a secure Darknet with WebRTC DataChannels in pure HTML, so I'm not interested about to know when an iframe has been fully loaded, but instead I'm interested to capture the iframe elements (inline images and so) using a custom scheme so I can be able from the parent page (the one connected to the Darknet) to do the real request and response with the actual data. With FirefoxOS mozbrowserlocationchange event of the Browser API objects (an extension to iframes) I could be able to capture the user navigation, cancel it, do the real request on the Darknet and later inject the iframe with the real content fetched by the parent page, but how could I be able to do the same with inline images and scripts on this loaded page? Or is this not currently possible and should I ask to them about add this functionality?
Obviously, I don't have any control about the iframes content pages, so they would be created by whatever and in any way, and also the usage of Browser API is just because seems to be the most useful to whan I'm trying to do, ideally it would be perfect if this is possible to achieve with plain iframes... :-)
Update:
A half-solution I have thinking about would be since I could be able to capture the mozbrowserlocationchange event to do the real content request of the HTML page and before fill the iframe with it do the request of their linked images and scripts and set them inline to prevent the iframe from doing more request. This would only lead to somewhat very simple web pages compared to current web standards (no AJAX, no async loading of script tags...) but definitely it would be usable up to some point :-)
Anyway, is there any other better alternative?
That sounds like something, that would be possible (straightforward, even) as soon as Service Controllers (previously known as NavigationControllers) are implemented, but I do not know any way to accomplish this via any currently available method.
No wonder you didn't find info about this - the proposal is called "Service workers" (though, previously this was called Event workers, and even before that, they were called - guess what - navigation controllers). This is a lively spec! ;) Find the working draft on GitHub: https://github.com/slightlyoff/ServiceWorker/ with a lengthy explainer document that should get you going.
Also, there is a document with the current Chrome (blink) implementation plans.
Certain websites like Twitter, Flickr, etc avoid being stuck within an iframe. Is there any way to stop this from happening? I just need to see the public data so I am open to disabling Javascript, etc. How do I disable Javascript running on the iframe? Is this possible?
You can't disable JavaScript on iFrames or any other resources AFAIK.
The only way to reliably do this is to load the sites through a proxy PHP or other server-side script, filter out any JavaScript (which will break many sites), and fix all relative references to images and other media - a task that would take an insane amount of time to complete if you want the sites to actually work.
If you just need some data from the sites, proxying might work. Seeing as the Same Origin Policy would prevent you getting anything from an IFRAME from a different domain anyway, it is also the only way to access content on those sites using JavaScript.
In IE only, there is the <iframe security="restricted"> attribute. This disables JavaScript in the targeted document, which would break a JS frame-escape script — along with all other interaction that's script-dependent.
However, apart from the browser compatibility issue, it's very rude to frame a site that doesn't want to be framed, and it will work less and less anyway as more sites deploy X-Frame-Options.
I'm not sure what you mean by “need to see the public data”... as Pekka said, you won't be able to ‘see’ into an iframe's DOM from outside it, as that would be a security problem.
I'm just looking for clarification on this.
Say I have a small web form, a 'widget' if you will, that gets data, does some client side verification on it or other AJAX-y nonsense, and on clicking a button would direct to another page.
If I wanted this to be an 'embeddable' component, so other people could stick this on their sites, am I limited to basically encapsulating it within an iframe?
And are there any limitations on what I can and can't do in that iframe?
For example, the button that would take you to another page - this would load the content in the iframe? So it would need to exist outwith the iframe?
And finally, if the button the user clicked were to take them to an https page to verify credit-card details, are there any specific security no-nos that would stop this happening?
EDIT: For an example of what I'm on about, think about embedding either googlemaps or multimap on a page.
EDIT EDIT: Okay, I think I get it.
There are Two ways.
One - embed in an IFrame, but this is limited.
Two - create a Javascript API, and ask the consumer to link to this. But this is a lot more complex for both the consumer and the creator.
Have I got that right?
Thanks
Duncan
There's plus points for both methods. I for one, wouldn't use another person's Javascript on my page unless I was absolutely certain I could trust the source. It's not hard to make a malicious script that submits the values of all input boxes on a page. If you don't need access to the contents of the page, then using an iframe would be the best option.
Buttons and links can be "told" to navigate the top or parent frame using the target attribute, like so:
This is a link
<form action="http://some.url/with/a/page" target="_parent"><button type="submit">This is a button</button></form>
In this situation, since you're navigating away from the hosting page, the same-origin-policy wouldn't apply.
In similar situations, widgets are generally iframes placed on your page. iGoogle and Windows Live Gadgets (to my knowlege) are hosted in iframes, and for very good reason - security.
If you are using AJAX I assume you have a server written in C# or Java or some OO language.
It doesn't really matter what language only the syntax will vary.
Either way I would advise against the iFrame methods.
It will open up way way too many holes or problems like Http with Https (or vice-versa) in an iFrame will show a mixed content warning.
So what do you do?
Do a server-side call to the remote site
Parse the response appropriately on the server
Return via AJAX what you need
Display returned content to the user
You know how to do the AJAX just add a server-side call to the remote site.
Java:
URL url = new URL("http://www.WEBSITE.com");
URLConnection conn = url.openConnection();
or
C#:
HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create("http://www.WEBSITE.com");
WebResponse res = req.GetResponse();
I think you want to get away from using inline frames if possible. Although they are sometimes useful, they can cause issues with navigation and bookmarking. Generally, if you can do it some other way than an iframe, that is the better method.
Given that you make an AJAX reference, a Javascript pointer would probably be the best bet i.e. embed what you need to do in script tags. Note that this is how Google embed things such as Google Analytics and Google Ads. It also has the benefit of also being pullable from a url hosted by you, thus you can update the code and 'voila' it is active in all the web pages that use this. (Google usually use version numbers as well so they don't switch everyone when they make changes).
Re the credit card scenario, Javascript is bound by the 'same origin policy'. For a clarification, see http://en.wikipedia.org/wiki/Same_origin_policy
Added: Google Maps works in the same way and with some caveats such as a user/site key that explicitly identify who is using the code.
Look into using something like jQuery, create a "plugin" for your component, just one way, and just a thought but if you want to share the component with other folks to use this is one of the things that can be done.