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/
Related
I noticed that GitHub and Facebook are both implementing this policy now, which restricts third party scripts from being run within their experience/site.
Is there a way to detect whether a document is running against CSP using JavaScript?
I'm writing a bookmarklet, and want to give the user a message if they're on a site that doesn't support embedding a script tag.
You can try to catch a CSP violation error using an event "securitypolicyviolation"
From: https://developer.mozilla.org/en-US/docs/Web/API/SecurityPolicyViolationEvent
example:
document.addEventListener("securitypolicyviolation", (e) => {
console.log(e.blockedURI);
console.log(e.violatedDirective);
console.log(e.originalPolicy);
});
What about this. For slow connections, the timeout should probably be raised. Onload is what I used to detect it and it seems to work. If it loads then CSP obviously isn't enabled or it is configured improperly.
var CSP = 0;
frame = document.createElement('script');
frame.setAttribute('id', 'theiframe');
frame.setAttribute('src', location.protocol+'//example.com/');
frame.setAttribute('onload', 'CSP=1;');
document.body.appendChild(frame);
setTimeout(function(){if (0 == CSP){alert("CSP IS ENABLED");}}, 250);
From https://github.com/angular/angular.js/blob/cf16b241e1c61c22a820ed8211bc2332ede88e62/src/Angular.js#L1150-L1158, function noUnsafeEval
function noUnsafeEval() {
try {
/* jshint -W031, -W054 */
new Function('');
/* jshint +W031, +W054 */
return false;
} catch (e) {
return true;
}
}
Currently, there is no way to do so in shipping browsers.
However, something such as the following should work, per spec, and does in Chrome with experimental web platform features enabled in chrome://flags/:
function detectCSPInUse() {
return "securityPolicy" in document ? document.securityPolicy.isActive : false;
}
The SecurityPolicy interface (what you get from document.securityPolicy if it is implemented) has a few attributes that give more detail as to what is currently allowed.
An easy way to detect support for CSP is just by checking if JavaScript's eval()-method can be run without throwing an error, like so:
try {
eval("return false;");
} catch (e) {
return true;
}
However, this only works if CSP is actually turned on (obviously), with Content-Security-Policy being set in the response headers the page loaded with, and without 'unsafe-eval' in script-src.
I came here looking for a way to detect CSP support in browsers without CSP actually being turned on. It would seem this is not possible though.
On a side note, IE does not support CSP, only the sandbox directive in IE 10+, which, by looking at the CSP standard, does not make it a conformant web browser.
From https://hackernoon.com/im-harvesting-credit-card-numbers-and-passwords-from-your-site-here-s-how-9a8cb347c5b5:
fetch(document.location.href)
.then(resp => {
const csp = resp.headers.get('Content-Security-Policy');
// does this exist? Is is any good?
});
This will fail however with connect-src='none' and be reported.
I am checking onError event in my bookmarklet code and prompt a user to install my extension if script is not loaded.
javascript:(function(){
var s=document.createElement('script');
s.setAttribute('type','text/javascript');
s.setAttribute('src','https://example.ru/bookmarklet?hostname=%27+encodeURIComponent(location.hostname));
s.setAttribute('onerror', 'if(confirm(`Downloading from the site is possible only through the "MyExtensionName" extension. Install extension?`)){window.open("https://chrome.google.com/webstore/detail/myextensionlink");}');
document.body.appendChild(s);})();
I'm new to web development and am trying to build a small webpage that'll attempt to detect if anyone's currently logged into Instagram on that browser. If I run my code command-by-command in Chrome's console and manually copy-paste the HTML, it works perfectly. But when I try to run my code separately, it seems to run as if it was in Incognito mode.
How would one get around this? If the user needs to grant my page permission to access Instagram, how would I do that?
Here's the JS part of my code:
const USERNAME_REGEX = /"viewer"\:{.*"full_name"\:"([^"]+)"/gm;
const FULLNAME = 'full_name\":\"';
document.addEventListener('DOMContentLoaded', () => {
const request = new XMLHttpRequest();
request.open('GET', 'https://instagram.com');
request.send();
request.onload = () => {
const data = request.responseText;
var u = data.match(USERNAME_REGEX);
if (u != null) {
u = u[0];
u = u.substring(u.indexOf(FULLNAME) + FULLNAME.length).slice(0, -1);
document.querySelector('#info').innerHTML = u;
}
else {
document.querySelector('#info').innerHTML = 'no one is logged in!';
}
}
});
Thank you :) have a wonderful day!
I'm new to web development and am trying to build a small webpage that'll attempt to detect if anyone's currently logged into Instagram on that browser.
That sounds like a security and privacy nightmare, which fortunately for everyone (you included) isn't possible. (Or at least, it shouldn't be...)
If I run my code command-by-command in Chrome's console and manually copy-paste the HTML, it works perfectly.
Totally different context. You'll find, in fact, that if you run this code in a console that isn't on Instagram.com, it won't work.
Same-origin policy will prevent you from accessing another domain. What you're attempting is a classic cross-origin attack that isn't going to work. CORS would get around this, but Instagram surely isn't going to enable you access.
How would one get around this?
You don't.
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.
I've made a component for an SAP solution (whatever) that is embedded into a report through an iframe. After I deployed the report on an SAP plateform (BO), I got this error (on Chrome, but does not work on IE or FF either):
Uncaught SecurityError: Blocked a frame with origin "http://support.domain.com" from accessing a frame with origin "http://support.domain.com". The frame requesting access set "document.domain" to "domain.com", but the frame being accessed did not. Both must set "document.domain" to the same value to allow access.
The iframe is embedded into my component so it's suppose to run on the same domain with same port than report.
I found this post on SO and this one, but it does not really helped me to understand what I need to do.
Is there a way to get rid of this, or at least work around this ?
Thanks :).
EDIT:
Host Page URL : http://support.domain.com/BOE/OpenDocument/opendoc/openDocument.jsp?sIDType=CUID&iDocID=AbmffWLjCAlFsLj14TjuDWg
URL of the file calling a property on the iframe (and generating the error) : http://support.domain.com/BOE/OpenDocument/1411281523/zenwebclient/zen/mimes/sdk_include/com.domain.ds.extension/res/cmp/js/component.js
URL of the frame :
http://support.domain.com/BOE/OpenDocument/1411281523/zenwebclient/zen/mimes/sdk_include/com.domain.ds.extension/res/cmp/js/map/js/map.html
The iframe embed itself some script tag, I can see everything loading fine in the Network tag of the console.
Maybe it can help.
EDIT 2 :
I just realized SAP report is itself embedded into an iframe. That means my iframe is within an iframe, that might be the issue. Still, when lauching the report from Eclipse, everything is working.
I've finally found a solution.
The top of my iframe had a domain.location set to domain.com and my iframe a domain.location set to support.domain.com.
Event though I still think that both belong to the same domain, browsers don't like it it seems so.
Re-setting the domain.location did the work.
To answer the ones asking about how to re-set location.domain, here is the snippet of code my team used to use. This is quite old (2y ago), not really optimized and we do not use it anymore, but I guess it's worth sharing.
Basically, what we were doing is load the iframe with passing it top domain in the URL parameters.
var topDomain = (function handleDomain(parameters) {
if (typeof parameters === "undefined") {
return;
}
parameters = parameters.split("&");
var parameter = [],
domain;
for (var i = 0; i<parameters.length; ++i) {
parameter.push(parameters[i]);
}
for (var j = 0; j<parameter.length; ++j) {
if (parameter[j].indexOf("domain") > -1) {
domain = parameter[j];
break;
}
}
if (typeof domain !== "undefined") {
domain = domain.split("=");
return domain[1];
}
return;
})(window.location.search),
domain = document.domain;
if (domain.indexOf(topDomain) > -1 && domain !== topDomain) {
document.domain = topDomain;
}
The previous answer is no longer valid:
Document.domain - https://developer.mozilla.org/en-US/docs/Web/API/Document/domain
Deprecated: This feature is no longer recommended. Though some browsers might still support it, it may have already been removed from the relevant web standards, may be in the process of being dropped, or may only be kept for compatibility purposes. Avoid using it, and update existing code if possible; see the compatibility table at the bottom of this page to guide your decision. Be aware that this feature may cease to work at any time.
The current solution would be to use message exchanges. See samples on:
The solution is https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage
I noticed that GitHub and Facebook are both implementing this policy now, which restricts third party scripts from being run within their experience/site.
Is there a way to detect whether a document is running against CSP using JavaScript?
I'm writing a bookmarklet, and want to give the user a message if they're on a site that doesn't support embedding a script tag.
You can try to catch a CSP violation error using an event "securitypolicyviolation"
From: https://developer.mozilla.org/en-US/docs/Web/API/SecurityPolicyViolationEvent
example:
document.addEventListener("securitypolicyviolation", (e) => {
console.log(e.blockedURI);
console.log(e.violatedDirective);
console.log(e.originalPolicy);
});
From https://github.com/angular/angular.js/blob/cf16b241e1c61c22a820ed8211bc2332ede88e62/src/Angular.js#L1150-L1158, function noUnsafeEval
function noUnsafeEval() {
try {
/* jshint -W031, -W054 */
new Function('');
/* jshint +W031, +W054 */
return false;
} catch (e) {
return true;
}
}
What about this. For slow connections, the timeout should probably be raised. Onload is what I used to detect it and it seems to work. If it loads then CSP obviously isn't enabled or it is configured improperly.
var CSP = 0;
frame = document.createElement('script');
frame.setAttribute('id', 'theiframe');
frame.setAttribute('src', location.protocol+'//example.com/');
frame.setAttribute('onload', 'CSP=1;');
document.body.appendChild(frame);
setTimeout(function(){if (0 == CSP){alert("CSP IS ENABLED");}}, 250);
Currently, there is no way to do so in shipping browsers.
However, something such as the following should work, per spec, and does in Chrome with experimental web platform features enabled in chrome://flags/:
function detectCSPInUse() {
return "securityPolicy" in document ? document.securityPolicy.isActive : false;
}
The SecurityPolicy interface (what you get from document.securityPolicy if it is implemented) has a few attributes that give more detail as to what is currently allowed.
An easy way to detect support for CSP is just by checking if JavaScript's eval()-method can be run without throwing an error, like so:
try {
eval("return false;");
} catch (e) {
return true;
}
However, this only works if CSP is actually turned on (obviously), with Content-Security-Policy being set in the response headers the page loaded with, and without 'unsafe-eval' in script-src.
I came here looking for a way to detect CSP support in browsers without CSP actually being turned on. It would seem this is not possible though.
On a side note, IE does not support CSP, only the sandbox directive in IE 10+, which, by looking at the CSP standard, does not make it a conformant web browser.
From https://hackernoon.com/im-harvesting-credit-card-numbers-and-passwords-from-your-site-here-s-how-9a8cb347c5b5:
fetch(document.location.href)
.then(resp => {
const csp = resp.headers.get('Content-Security-Policy');
// does this exist? Is is any good?
});
This will fail however with connect-src='none' and be reported.
I am checking onError event in my bookmarklet code and prompt a user to install my extension if script is not loaded.
javascript:(function(){
var s=document.createElement('script');
s.setAttribute('type','text/javascript');
s.setAttribute('src','https://example.ru/bookmarklet?hostname=%27+encodeURIComponent(location.hostname));
s.setAttribute('onerror', 'if(confirm(`Downloading from the site is possible only through the "MyExtensionName" extension. Install extension?`)){window.open("https://chrome.google.com/webstore/detail/myextensionlink");}');
document.body.appendChild(s);})();