Javascript Iframe Security Error Within Try/Catch Block In Webkit Browsers - javascript

When I run the following code in webkit browsers, I get an error outputted to the console despite having my code wrapped in a try/catch block.
var externallyFramed = false;
try {
externallyFramed = top.location.host != location.host;
} catch (e) {
externallyFramed = true;
}
The error I get is the following:
Unsafe JavaScript attempt to access frame with URL...
Is there anything I can do differently to prevent the error from showing up?

Related

ParseFromString throws error in IE, but not in Chrome

I'm using a KML plugin for leaflet that works great in Google Chrome. In IE, however, It throws an error at the following code.
parser=new DOMParser();
console.log(url) // outputs: "path/to/kmlfile.kml" in Chrome debugger
url=parser.parseFromString(url,"text/xml"); //This line throws a parser error in IE 11, but is fine in Chrome
It seems to me that there is a mistake in this code - the author should pass an actual XML string, not just a url to an XML document to the parser.parseFromString() function. It makes sense that the parser would have an error, as a path to a file is not a valid XML file (Note: kml files are just XML). However, this does not cause any errors to be thrown in the Chrome Debugger tools, which is really strange.
It seems to me that this should fail in both instances. Trusty MDN docs on DOMParser have no mention of putting a URL as a parameter in parseFromString(). So my question is why is this working in Chrome, but throwing an error in IE, and then what can I do to fix it?
Note this question is different from the following url because this isn't a general error - this is about something that works in Chrome but fails in IE: Internet Explorer 11 (IE 11) Throws Syntax Error using parseFromString in DOMParser
When the XML is malformed non-Microsoft browsers (Firefox, Chrome, etc) it will create the XML document with the error message as it's content. Click here (<-- click there).
When the XML is malformed in Microsoft browsers, IE and Edge, it throws an error, writes an error to the console and your script stops. Note I'm on a Mac so I've tested this remotely but have not had a chance to test it personally. You can put that code in a try catch block for IE but what I mean is I don't know if that will stop it from writing a message to the console.
Here's the code pen with intentionally malformed XML and the error message is written in the output. There is no error in the codepen or output. I'm intentionally writing the error code from the parser to the output window. Open the console to see what's going on.
FWIW IE is the correct behavior IMHO. Not throwing errors was the Internet way to do things until relatively recently. The problem with not throwing errors is you don't know what you did wrong or where. Write once, debug everything.
Also, until more recent versions, IE used ActiveX to parse XML documents.
From W3C XML validation script:
function validateXML(text) {
var message;
var parser;
var xmlDoc;
// code for Edge, IE, Mozilla, Firefox, Opera, etc.
if (document.implementation.createDocument || window.DOMParser) {
parser = new DOMParser();
try {
xmlDoc = parser.parseFromString(text, "text/xml");
}
catch (error) {
}
if (xmlDoc.getElementsByTagName("parsererror").length > 0) {
return xmlDoc.getElementsByTagName("parsererror")[0];
}
else {
return "No errors found";
}
}
// code for older versions of IE
else if (window.ActiveXObject) {
xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
xmlDoc.async = "false";
try {
xmlDoc.loadXML(text);
}
catch (error) {
}
if (xmlDoc.parseError.errorCode != 0) {
message = "Error Code: " + xmlDoc.parseError.errorCode + "\\n";
message = message + "Error Reason: " + xmlDoc.parseError.reason;
message = message + "Error Line: " + xmlDoc.parseError.line;
return message;
}
else {
return "No errors found";
}
}
else {
return "Not supported";
}
}
Related question.

Get around same-origin policy to get top URL of a page from inside a cross-domain iframe

I've got some code running in an iframe on 3rd-party sites. Some will be directly in the top page, some will be inside another iframe and some of these may be cross-domain. I need to find a way to get the URL value of the top page using any means necessary.
The furthest I can go up due to cross-domain policy is until the browser stops what the code is doing. I catch the error and look at the referrer of the current window context I'm in. Most cases the page above this is the top page, but not necessarily.
The only way I can see around this is building up a list of URLs which I think are the top page, and then sending a bot with a JS browser validate by seeing if the iframe my code got up to was in fact directly nested in them.
That's still not particularly accurate though, and I'm sure there must be another way of doing it...
Thanks to anyone who can help.
There is actually a way to get the domain in both Chrome and Opera, (in multiple nested cross-domain iframes), though it is not possible in other browsers.
You need to use the 'window.location.ancestorOrigins' property.
I have created a snippet of code below, which should work for you and if you think you can improve the code or comments, please don't hesitate to edit the gist on Github so we can make it even better:
Gist: https://gist.github.com/ocundale/281f98a36a05c183ff3f.js
Code (ES2015):
// return topmost browser window of current window & boolean to say if cross-domain exception occurred
const getClosestTop = () => {
let oFrame = window,
bException = false;
try {
while (oFrame.parent.document !== oFrame.document) {
if (oFrame.parent.document) {
oFrame = oFrame.parent;
} else {
//chrome/ff set exception here
bException = true;
break;
}
}
} catch(e){
// Safari needs try/catch so sets exception here
bException = true;
}
return {
'topFrame': oFrame,
'err': bException
};
};
// get best page URL using info from getClosestTop
const getBestPageUrl = ({err:crossDomainError, topFrame}) => {
let sBestPageUrl = '';
if (!crossDomainError) {
// easy case- we can get top frame location
sBestPageUrl = topFrame.location.href;
} else {
try {
try {
// If friendly iframe
sBestPageUrl = window.top.location.href;
} catch (e) {
//If chrome use ancestor origin array
let aOrigins = window.location.ancestorOrigins;
//Get last origin which is top-domain (chrome only):
sBestPageUrl = aOrigins[aOrigins.length - 1];
}
} catch (e) {
sBestPageUrl = topFrame.document.referrer;
}
}
return sBestPageUrl;
};
// To get page URL, simply run following within an iframe on the page:
const TOPFRAMEOBJ = getClosestTop();
const PAGE_URL = getBestPageUrl(TOPFRAMEOBJ);
If anybody would like the code in standard ES5, let me know, or simply run it through a converter online.
Definitely not possible without communicating with some sort of external system. The cleanest/most accurate way to gather data is to get the top window URL if the browser lets you, but catch errors and use the referer with a flag to note it's the referer.

ActiveXObject works when running from .NET but fails after publish

I have an HTML page that has a link to open Microsoft Word on the local machine. The code runs fine while I am running in .NET. Once it is published to a server, ActiveXObject fails without returning any message or Inner Exception.
Has anyone else encountered this before. Since this is running at the client in javascript, I don't understand why it would fail.
function WordCallback(filename) {
var word;
try {
word = new ActiveXObject("Word.Application"); //fails here
}
catch (e) {
$.colorbox.close();
alert('This functionality only works with Internet Explorer.');
return false;
}
try {
//open the document using word
word.Documents.Open(filename);
word.Visible = true; // Make sure Word is visible.
word.Activate();
}
catch (e) {
alert('Unable to open the document.');
}
return false;
}
Its most likely failing because
the client does not have Word installed
the server/site is not trusted
the browser's security does not allow ActiveXObject's to be created
The most likely error is that your server/site is not trusted by the browser. See Allowing ActiveXObject for a trusted site or http://support.microsoft.com/kb/832512

Catch X-Frame-Options Error in javascript

Is there any way to catch an error when loading an iframe from another domain. Here is an example in jsfiddle. http://jsfiddle.net/2Udzu/ . I need to show a message if I receive an error.
Here is what I would like to do, but it doesn't work:
$('iframe')[0].onerror = function(e) {
alert('There was an error loading the iFrame');
}
Anyone have any ideas?
The onerror is applicable only for script errors. Frame content error checking must be done using any other method. Here's one example.
<script>
function chkFrame(fr) {
if (!fr.contentDocument.location) alert('Cross domain');
}
</script>
<iframe src="http://www.google.com/" onload="chkFrame(this)"></iframe>
Due to cross domain restriction, there's no way to detect whether a page is successfully loaded or if the page can't be loaded due to client errors (HTTP 4xx errors) and server errors (HTTP 5xx errors).
If both the parent site and the iframe-url is accessible by you, a way to know that the page is fully loaded (without "sameorigin" issues) is sending a message (postMessage) from the child to the parent like this;
Parent site (containing the iframe)
//Listen for message
window.addEventListener("message", function(event) {
if (event.data === "loading_success") {
//Yay
}
});
//Check whether message has come through or not
iframe_element.onload = function () {
//iframe loaded...
setTimeout(function() {
if (!iframeLoaded) {
//iframe loaded but no message from the site - URL not allowed
alert("Failure!");
}
}, 500);
};
Child site (URL from the iframe)
parent.postMessage("loading_success", "https://the_origin_site.url/");
You could get the_origin_site.url by using a server-side language like PHP if you want the possibility for multiple origins
The accepted answer only works if the domain you're trying to put in an iframe is the same as the one you're requesting from - this solution works for cross-domain where you have access to the scripts on both domains.
I am using following code to detect whether a x-frame-option error occured or another with jquery
$(iframe).load(function (e) {
try
{
// try access to check
console.log(this.contentWindow.document);
// Access possible ...
}
catch (e)
{
// Could not access. Read out error type
console.log(e);
var messageLC = e.message.toLowerCase();
if (messageLC.indexOf("x-frame-options") > -1 || messageLC.indexOf('blocked a frame with origin') > -1 || messageLC.indexOf('accessing a cross-origin') > -1)
{
// show Error Msg with cause of cross-origin access denied
}
else
{
// Shoe Error Msg with other cause
}
}
});

Unsafe javascript attempt not caught by try block

I have an iframe nested in my main page. The iframe contains the following script:
var adfoxPlaceholderId = 'placeholder';
var adfoxWindow = window;
var adfoxDocument = window.document;
var adfoxPlaceholder = adfoxDocument.getElementById(adfoxPlaceholderId);
try {
while((adfoxPlaceholder == null) && (adfoxWindow != window.top)) {
adfoxWindow = adfoxWindow.parent;
adfoxDocument = adfoxWindow.document;
adfoxPlaceholder = adfoxDocument.getElementById(adfoxPlaceholderId);
}
} catch(ex) {
console.log('catch-block');
}
The script breaks on line adfoxDocument = adfoxWindow.document; because of the security policy (the iframe and the main page are from different urls).
My question is why isn't this error caught by catch block as if it wasn't put into the try-catch block? Thank you.
This is happening because it's not a javascript exception. It's a browser security feature. This is happening because your iframe and your website dont have the same URL.
source of Same Origin Policy can be found here.
That being said, there are way to "circumvent" this policy via third party tools or javascript tricks
here are a few options"
easyXDM
ways-to-circumvent-the-same-origin-policy
I hope that helps
This does not happen in my tests. Testing on IE, FF, Chrome and Safari. The error is not in the code you've posted in your question.
http://jsfiddle.net/hg2cs/1/

Categories