JavaScript document.domain Uncaught DOMException: Blocked a frame with origin - javascript

While I was testing the SOP, i came to this scenario two documents has a relationship with the same domain as i would expected and it throws an error when i try to get the location.
To reproduce the problem:
Open https://www.google.com
from the console let opened = window.open("https://www.google.com")
from the same window do opened.location.toString() which will return the correct location
from the second tab's console do document.domain = "www.google.com"
from the first tab do opened.location.toString() and you will get an error
Uncaught DOMException: Blocked a frame with origin "https://www.google.com" from accessing a cross-origin frame.
at <anonymous>:1:12
Can anyone explain this strange behavior?

This error is not a bug. The same-origin policy is a security mechanism that ensures that window objects only have access to the informations they are authorized to get. In your case, this includes having access to opened.location.
Upon creation, both tabs have the same origin, which allows the first one to access opened.location. But after the call to document.domain='www.google.com', they don't anymore.
"What? But in both tabs, window.location.origin are identical"
Yes, but it is a little bit more complex. The origin is defined by the scheme/host/port tuple, see #TheUnknown's answer for more details. The scheme and host stay the same all along, and they're the one included in the string of window.location.origin.
The tricky thing to know is that any call to document.domain, including document.domain = document.domain, causes the port number to be overwritten with null, therefore causing a difference in the two tabs' origins, and preventing them from communicating informations like opened.location with one another, thus the error.
Informations extracted from MDN's guide on same-origin policy

First, I would recommend, you read Same-origin Policy.
The same-origin policy is a critical security mechanism that restricts
how a document or script loaded from one origin can interact with a
resource from another origin. It helps isolate potentially malicious
documents, reducing possible attack vectors.
Two URLs have the same origin if the protocol, port (if specified), and host are the same for both. You may see this referenced as the "scheme/host/port tuple", or just "tuple". (A "tuple" is a set of items that together comprise a whole — a generic form for double/triple/quadruple/quintuple/etc.)
In this particular case, you open a window with HTTPS protocol, however when you set the domain, the protocol is changed to HTTP, see image below:
As per 1, if the protocols are not the same, then its a violation of the principle and hence you get the error
Uncaught DOMException: Blocked a frame with origin
"https://www.google.com" from accessing a cross-origin frame.
cross-origin is the keyword here.
Also, check out this SecurityError: Blocked a frame with origin from accessing a cross-origin frame for more details.

This will be a bit uninformative (just states facts), nevertheless:
After you change domain in window B, window B stops accounting window A as opener.
Since window A is no longer considered an opener of window B, the access is prohibited.
This makes me think, that altering document.domain is considered potentially insecure and is "punished" by orphaning the child window.

Related

Uncaught DOMException: Blocked a frame with origin "http://localhost:8080" from accessing a cross-origin frame while listing the iframes in page

I am trying to list the names of all the iframes in a page, so I can access them through Selenium.
The problem is that the name of the iframe changes each time, so I need to loop through all of them.
I am getting:
Uncaught DOMException: Blocked a frame with origin "http://localhost:8080" from accessing a cross-origin frame.
error when I try to loop over them using:
for (var f = 0; f < window.frames.length; f++) {
console.log(window.frames[f].name)
}
Is there a way to get the name of the iframe in a different way?
This error message...
Uncaught DOMException: Blocked a frame with origin "http://localhost:8080" from accessing a cross-origin frame.
...implies that the WebDriver instance blocked from accessing a cross-origin frame.
Same-origin policy
Same-origin policy : Same-origin policy restricts how a document or script loaded from one origin can interact with a resource from another origin. It is a critical security mechanism for isolating potentially malicious documents.
Cross-Origin Resource Sharing (CORS)
Cross-Origin Resource Sharing (CORS) : Cross-Origin Resource Sharing (CORS) is a mechanism that uses additional HTTP headers to tell a Browser Client to let the AUT (Application under Test) running at one origin (domain) have permission to access selected resources from a server at a different origin. A web application makes a cross-origin HTTP request when it requests a resource that has a different origin (domain, protocol, and port) than its own origin.
Example of an origin
Here is an example of origin comparisons to the URL http://store.company.com/dir/page.html
URL Outcome Reason
http://store.company.com/dir2/other.html Success
http://store.company.com/dir/inner/another.html Success
https://store.company.com/secure.html Failure Different protocol
http://store.company.com:81/dir/etc.html Failure Different port
http://news.company.com/dir/other.html Failure Different host
What went wrong
When you tried to loop through frames your script/program tried to access an <iframe> with different origin using JavaScript which would been a huge security flaw if you would have achieved it. As mentioned above the same-origin policy browsers block scripts trying to access a <iframe> with a different origin.
Two pages have the same origin if the protocol, port (if one is specified), and host are the same for both the webpages. You'll see this referred to as the "scheme/host/port tuple" at times (where a "tuple" is a set of three components that together comprise a whole). Perhaps the protocol, domain, hostname and port must be the same of your same domain when you want to access the desired frame.
Solution
The AUT may contain numerous frames / iframes and some of them may be loaded only after certain JavaScript / Ajax have completed where as some of them may be having style attribute set as display:none; or visiblity as hidden. Of-course won't require to interact with all of them. So it will be a better approach to identify the attributes of the <iframe> and switch accordingly. You can switch to an <iframe> through:
Frame Name
Frame ID
Frame Index
WebElement
As per best practices when you intent to switch to a frame induce WebDriverWait for frameToBeAvailableAndSwitchToIt as per the references below.
Here you can find a relevant discussion on Uncaught DOMException
References
Some references:
In this discussion you will find a detailed analysis on SecurityError: Blocked a frame with origin from accessing a cross-origin frame
In this discussion you will find the different approaches on Is it possible to switch to an element in a frame without using driver.switchTo().frame(“frameName”) in Selenium Webdriver Java?
In the A Better Approach to Switch Frames section of this discussion you will find the different approaches on How can I select a html element no matter what frame it is in in selenium?
You can try something like this : (Not sure about JavaScript)
var iframeElems = driver.findElements(webdriver.By.tagName("iframe"));
iterate this list to get the attribute.
for (var f = 0; f < iframeElems.length; f++) {
console.log(iframeElems.getAttribute("attribute name"))
}
Dirty solution:
for windows:
chrome.exe --user-data-dir="" --disable-web-security
for mac:
open -a Google\ Chrome --args --disable-web-security --user-data-dir=""
In this way you open the chrome and let it ignore the web security.
You can use selenium to get iframe tags like this:
var iframeElems = driver.findElements(webdriver.By.xpath("//iframe"));
Then loop on those elements and get the name attribute:
iframe.getAttribute('name')

Allowing cross-site requests between subdomains without changing file contents of second sub domain

I am currently attempting to wrap a web application (ConnectWise) for inclusion within my company's central intranet site. It's a fairly simple process for the most part; create a containing page, with an iframe, point the iframe at the ConnectWise url. This part works for almost all of the functionality.
The problem comes during certain select features of the app (in this case, part of the process of creating a timesheet entry), which simply fail to work. Chrome gives the following console output.
Uncaught SecurityError: Failed to read the 'frame' property from 'Window': Blocked a frame with origin "https://app.example.com" from accessing a frame with origin "https://host.example.com". Protocols, domains, and ports must match.
I am aware this is caused by the security options for cross-site and same-origin policies. Given the following points, is there a way to overcome this?
I have full control over https://host.example.com
I can change html, javascript, and file contents
I can change IIS settings and headers
I have partial control over https://app.example.com
I can not change html, javascript, and file contents
I can change IIS settings and headers.
I have tried setting the Access-Control-Allow-Origin on each server, which so far is the only method I've come across that does not involve being able to change the file contents for the app server. This does not appear to work when given the settings (and combinations of settings) of
* or https://app.example.com while on https://host.example.com
* or https://host.example.com while on https://app.example.com
Edit:
The solution to this "duplicate" question is not applicable here. I do not have access to change file contents (including javascript) of the iframed page (app.example.com). Additionally, the script requiring the permission to run is the page within the iframe, not the page hosting the iframe.
CORS headers such as Access-Control-Allow-Origin only affect AJAX requests, not DOM access.
However, If they are both on the same domain but different subdomains then you can include the following on each page:
document.domain = 'example.com';
From MDN:
One document is allowed to access another if they have both set
document.domain to the same value, indicating their intent to
cooperate
If app.example.com has any script includes to host.example.com then you could put the above code in those scripts to set the domain.
e.g.
<script src="https://host.example.com/setup.js"></script>
No, it is not possible.
Access-Control-Allow-Origin primarily affects getting raw data from HTTP requests, not live DOMs.
postMessage can let frames on different origins communicate, but it requires JS to be included on both pages.

Unsafe JavaScript Attempt when trying to reload frame

This is annoying. I am trying to make it so that when the I press F5, the frame reloads. I have got it so that if the focus is on the main page (not the iframe) it works. However, when I try to implement a similar solution or even make any attempt to communicate with the iframe, I get an 'Unsafe JavaScript attempt to access frame'. To be more specific, the exact error is:
Unsafe JavaScript attempt to access frame with URL http://www.spow.tk/projects/test from frame with URL http://spow.tk/projects/Explorer/02/. Domains, protocols and ports must match.
Please help as this really is a pain.
Thanks
Those two sites are on different domains. Due to security restrictions in Javascript, you cannot script across domains. Check out Wikipedia or Mozilla for more info (quoted Mozilla to prevent link rot):
The same origin policy prevents a document or script loaded from one origin from getting or setting properties of a document from another origin. This policy dates all the way back to Netscape Navigator 2.0.
Mozilla considers two pages to have the same origin if the protocol, port (if one is specified), and host are the same for both pages. The following table gives examples of origin comparisons to the URL http://store.company.com/dir/page.html:
URL Outcome Reason
http://store.company.com/dir2/other.html Success
http://store.company.com/dir/inner/another.html Success
https://store.company.com/secure.html Failure Different protocol
http://store.company.com:81/dir/etc.html Failure Different port
http://news.company.com/dir/other.html Failure Different host
There is one exception to the same origin rule. A script can set the value of document.domain to a suffix of the current domain. If it does so, the shorter domain is used for subsequent origin checks. For example, assume a script in the document at http://store.company.com/dir/other.html executes the following statement:
document.domain = "company.com";
After that statement executes, the page would pass the origin check with http://company.com/dir/page.html. However, by the same reasoning, company.com could not set document.domain to othercompany.com.
Port number is kept by the browser separately. Any call to the setter, including document.domain = document.domain causes the port number to be overwritten with null. Therefore one can not make company.com:8080 talk to company.com by only setting document.domain = "company.com" in the first. It has to be set in both so that port numbers are both null.
spow.tk and www.spow.tk are considered to be different domains.
One thing you can do however, is to force your site to use one or the other, so that this issue doesn't arise again. For instance, if you're using Apache, you can modify your .htaccess to redirect all requests from spow.tk to www.spow.tk (or www.spow.tk to spow.tk if that's what you prefer). Even if your users or code reference one domain, the request will be redirect to the domain you specified.

error : Permission denied to access property 'document'

How can I fix this message in Firefox? I am using an Iframe which has an anchor tag? I would like to get a reference to this anchor but i am getting this error when I am trying to access anchor:
var frameWindow = document.getElementById('myIframe').contentWindow;
var anchor = frameWindow.document.links[0]; //.getElementsByClassName('a');
anchor.onclick....
Relaxing the same-origin policy
In some circumstances the same-origin policy is too restrictive, posing problems for large websites that use multiple subdomains. Here are four techniques for relaxing it:
document.domain property
If two windows (or frames) contain scripts that set domain to the same value, the same-origin policy is relaxed for these two windows, and each window can interact with the other. For example, cooperating scripts in documents loaded from orders.example.com and catalog.example.com might set their document.domain properties to “example.com”, thereby making the documents appear to have the same origin and enabling each document to read properties of the other. This might not always work as the port stored in the internal representation can become marked as null. In other words example.com port 80 will become example.com port null because we update document.domain. Port null might not be treated as 80 ( depending on your browser ) and hence might fail or succeed depending on your browser.
Cross-Origin Resource Sharing
The second technique for relaxing the same-origin policy is being standardized under the name Cross-Origin Resource Sharing. This draft standard extends HTTP with a new Origin request header and a new Access-Control-Allow-Origin response header. It allows servers to use a header to explicitly list origins that may request a file or to use a wildcard and allow a file to be requested by any site. Browsers such as Firefox 3.5 and Safari 4 use this new header to allow the cross-origin HTTP requests with XMLHttpRequest that would otherwise have been forbidden by the same-origin policy.[7]
Cross-document messaging
Another new technique, cross-document messaging allows a script from one page to pass textual messages to a script on another page regardless of the script origins. Calling the postMessage() method on a Window object asynchronously fires an "onmessage" event in that window, triggering any user-defined event handlers. A script in one page still cannot directly access methods or variables in the other page, but they can communicate safely through this message-passing technique.
JSONP
JSONP allows a page to receive JSON data from a different domain by adding a <script> element to the page which loads a JSON response from a different domain.
The function call is the "P" of JSONP—the "padding" around the pure JSON, or according to some the "prefix". By convention, the browser provides the name of the callback function as a named query parameter value, typically using the name jsonp or callback as the named query parameter field name, in its request to the server, e.g.,
<script type="application/javascript"
src="http://server2.example.com/Users/1234?jsonp=parseResponse">
</script>
In this example, the received payload would be:
parseResponse({"Name": "Foo", "Id": 1234, "Rank": 7});
If the iframe points to a different domain, you will get this error. This is an example of your browser preventing cross-site scripting: http://en.wikipedia.org/wiki/Cross-site_scripting
The error is due to the same-origin policy like explained in other answers. I post this answer as a workaround to execute JavaScript code in a web console.
My comment suggesting to use Firebug CD command no longer works because Firebug is not supported anymore.
But there is a similar feature in Firefox Developer Tools, you can switch the domain name by selecting the iframe context picker button like described here: https://developer.mozilla.org/en-US/docs/Tools/Working_with_iframes

Can I tell if a frame access will be cross-domain before performing it?

I am trying to find the DOM iframe or frame element for each of the frames in a window's frames collection. The fastest way to do this, I think, is to access the frame's frameElement property. This property is only available for a same-domain access, and returns undefined and prints an error message to the log in the cross-domain case.
I can loop through the elements returned from document.getElementsByTagName to find the correct element in the cross-domain case, but I'd like to avoid printing the "Unsafe JavaScript attempt" message to the log.
Is there any way to tell before trying it if a property access attempt will run afoul of the cross-domain security policy?
Thanks.
You could check the domain on the url of the hosting page and the frame (src property). If the domains differ, you will most likely get an error.
I say most likely because if the frame is on a subdomain, but has specified document.domain to be the same as the parent frame, then cross-domain access will work.

Categories

Resources