The JavaScript single-page application I am maintaining opens most of the times in iframes created inside pages of our customers' sites.
Our SPA features a brutal override of window.onerror, as I want to be notified on my server of all JS errors happening during the execution of my code.
window.onerror = my_global_error_handler;
When JS code fails I record the domain where it came from. I'd expect that all errors be generated from code coming from my company's domain.
However, in some cases I get errors generated from JS code loaded from other domains. I wonder how this is possible, as I expect that my error handler be unable to catch errors outside the iframe where my code is executing.
Since most of the "foreign" domains mentioned in my logs are various viral e-marketing companies, I wonder whether some smart kid is managing to inject code in my iframe.
Another hypothesis is that some browsers may be overriding the top window's error handler when I override the one of the inner iframe window.
What could be happening?
Related
I am currently trying to detect if a user has a certain Chrome extension installed. The Chrome extension is not my own and I do not have the source code to it. I have tried methods in numerous posts but they all fail. What I've tried and why it failed is detailed below.
This results in 'cannot read property connect of undefined' when executed:
var myPort=chrome.extension.connect('idldbjenlmipmpigmfamdlfifkkeaplc', some_object_to_send_on_connect);
Trying to load a resource of the extension as follows to test if it's there but going to this URL in browser results in 'your file was not found' Chrome error page (note that I found this path by going to C:\Users\\AppData\Local\Google\Chrome\User Data\Default\Extensions\idldbjenlmipmpigmfamdlfifkkeaplc\1.0.0.1_0\ on my Windows local machine):
chrome-extension://idldbjenlmipmpigmfamdlfifkkeaplc/1.0.0.1_0/icon_16.png
Using Chrome management but this results in console error 'cannot read property get of undefined' when executed
chrome.management.get("idldbjenlmipmpigmfamdlfifkkeaplc", function(a){console.log(a);});
And most other answers I've come across seem to involve the extension being written by the same person who is trying to check for it.
Assuming you need it from a website
connect/message method implies that the extension specifically listed your website in the list of origins it expects connection from. This is unlikely unless you wrote this extension yourself, as this cannot be a wildcard domain.
Referring to files within the extension from web context will return 404 simulate a network error unless the extension declared them as web-accessible. This used to work before 2012, but Google closed that as a fingerprinting method - now extensions have to explicitly list resources that can be accessed. The extension you specifically mention doesn't list any files as web-accessible, so this route is closed as well.
chrome.management is an extension API; websites cannot use it at all.
Lastly, if an extension has a content script that somehow modifies the DOM of your webpage, you may detect those changes. But it's not very reliable, as content scripts can change their logic. Again, in your specific case the extension listens to a DOM event, but does not anyhow make clear the event is received - so this route is closed.
Note that, in general, you cannot determine that content script code runs alongside yours, as it runs in an isolated context.
All in all, there is no magic solution to that problem. The extension has to cooperate to be discoverable, and you cannot bypass that.
Assuming you need it from another extension
Origins whitelisted for connect/message method default to all extensions; however, for this to work the target extension needs to listen to onConnectExternal or onMessageExternal event, which is not common.
Web-accessible resources have the same restrictions for access from other extensions, so the situation is not better.
Observing a page for changes with your own content script is possible, but again there may be no observable ones and you cannot rely on those changes being always the same.
Similar to extension-webpage interaction, content scripts from different extensions run in isolated context, so it's not possible to directly "catch"code being run.
chrome.management API from an extension is the only surefire way to detect a 3rd party extension being installed, but note that it requires "management" permission with its scary warnings.
Question first:
Is it possible to get iframe contents when it's displaying a browser error document (page not found, connection lost, certificate problem...)?
Problem explained:
I've built a simple form with an iframe inside. This iframe has a simple file upload form that works great in every test I have done. BUT the form is meant to be used inside a company's network and some users are reporting random problems when sending the iframe upload form from inside the network. I suspect that they are receaving lost connections because of internal network malfunctions and the iframe gets blank after sending (because the size is too small to display the error document and scrollbars are disabled).
As I'm not able to reproduce the errors I need to debug the process with Javascript, logging what is loaded inside the iframe after an error occurs to a user.
Actually I use jQuery to retrieve iframe's content:
$("#iframeid").contents().find("body").html();
Works great when retrieving a regular html document but not when trying to retrieve a browser error document. In this case I get the error:
Permission denied to access property "document"
Why is this happening? Because of same origin policy? Is there any way to override this?
Why is this happening? Because of same origin policy?
Yes.
Is there any way to override this?
No.
The browser does not allow you to read the contents of an internal document, like a 404 page. You will want to configure your webserver or fastcgi to return a soft 404 page which would allow you to view the contents of the iframe.
What do these drop downs do? I assume they execute console commands in different contexts but I see weird, nonsensical choices when I click them.
Lets take Gmail as an example and start by looking at the first drop down:
List of frames
What you can see here are all frames that are embedded into the current page. Each of these frames is sandboxed. Being sandboxed means that there is no access from one sandbox to the other sandboxes. Scripts executed inside one frame can't access DOM or JS variables of the other frame. This is due to security reasons, we don't want a script inside an iframe to have access to the page it was embedded in (this would allow e.g. ads embedded into a blog to read what you are typing or what you keep in your cookies).
List of contexts
In the second drop down we have list of contexts for selected frame e.g. here is a list of contexts for Gmails <top frame>:
These are sandboxes created for each script that was injected by Chrome extension to the selected frame (these scripts are known as 'content scripts'). However, these are different from the frame sandboxes that I've mentioned before. Scripts injected by Chrome extensions have unlimited access to the DOM of the page they were injected to but operate in a separate JS execution context called isolated world (don't have access to "JavaScript variables or functions created by the page"). In this case it's more about making sure that scripts from different extensions don't interfere with each other than about the security:
Isolated worlds allow each content script to make changes to its
JavaScript environment without worrying about conflicting with the
page or with other content scripts. For example, a content script
could include JQuery v1 and the page could include JQuery v2, and they
wouldn't conflict with each other.
BTW Part of the url after chrome:// represents extension ID and using it you can figure out the name of the extension that injected the code (check 'Developer mode' on the chrome://extensions/ page).
Why do we need that?
You may want to see errors / console.* messages generated by an iframe.
While debugging your Chrome extension you may want to see errors / console.* messages that your injected script have produced.
You may want to execute some code from console in context different than the default one.
I've made a site which handles online credit card payments. As part of the payment process an iframe is required on my site which works with an external security service to validate credit card data. I need to pass specific information to this iframe which it will use in a form post. I do this from my site by calling a function on this iframe, as follows:
var frame = window.frames["SecureFrame"];
frame.SetInnerFormValues(...);
This works fine in my dev environment. However, my site also needs to be run as an iframe on any client sites. So in the end, the client site will have an iframe pointing to my payment interface, which has a iframe pointing to the secure service. Both of these iframes are of course using SSL.
This seems to create an issue with the multiple nested frames on the client side. (Well, Chrome works fine, but Firefox doesn't)
When an end user is on a client site, an error occurs when my JS code above is executed. Firefox throws an error saying "TypeError: frame.SetInnerFormValues is not a function". I tried executing some code in the JS console to attempt to get to this SetInnerFormValues function on the secure frame, but all I'm getting is "Error: Permission denied to access property '...'" when just trying to access anything on my own site first.
Please, Ninja's of SO, I need your help!
Since the iFrame is loaded from another website, you can't do regular javascript function calls on it. That would be cross-site scripting (XSS). You need to set up an interface on your server that responds to SSL-secured (https:) POST requests to keep your users' information safe.
I am trying to load asynchronously the connect.facebook.net/en_US/all.js script , see here
The problem is that fbAsyncInit is never get called...
This is because 'window' in a content script is not the real window, but a proxy. I can get your code working by replacing window with 'unsafeWindow':
https://builder.addons.mozilla.org/package/157253/latest/
Note that this introduces a possible security issue - in particular you should not trust any data that comes form unsafeWindow or anything attached to it. This is a hack that can be used to get things working in cases where the the proxy will not, but could be used to allow web pages to execute arbitrary code with the privileges of the browser.