Edit cross-domain Iframe content Locally Only - javascript

As many of us know there is no way to edit a Cross Domain IFrame due to the Same Origin Policy.
Is there a way around this if we use the Stylish extension etc. locally only?
Take this video being launched inside an iframe for example:
I need to simply add "zoom:2;" onto "#video21588864 iframe figure"
If this is 100% not possible, why am I able to do it successfully in the Inspector window, but not automatically? Is there really ZERO automatic local ways around this using Javascript or something?

There is no way you can access the content inside the <iframe> in a cross-origin fashion. You might be able to if the response includes a CORS header.
Why am I able to do it successfully in the Inspector window
The developer tools is separate from your document. It can do much more things that you cannot possibly do with normal JavaScript in a webpage.
Rationale
There is a reason why you cannot access the content inside an iframe. Consider this, a user was logged into their bank webpage. A token is stored in a cookie to prove that the user is logged in.
Now you include an iframe in your webpage and loads the bank's webpage. Since the cookie contains a valid token, the iframe will show that the user has been logged in.
Wouldn't it be great if you can access the iframe and send yourself some money? Well, this is exactly why it's not allowed, 100% not possible, given that the browser is implemented correctly.
Addendum
I have decided to add this part after seeing that you have mentioned the word locally. Now, I do not know exactly what you are trying to do, but it is possible to manipulate the content inside the iframe if you have an elevated privilege, including:
a userscript
an extension with proper permissions acquired
developer tools
the browser itself
If you merely want to add zoom: 2 to videos from ESPN on your own computer, I would suggest creating a userscript which has a much higher privilege than a normal webpage and much easier to make than an extension.
// ==UserScript==
// #match http://www.espn.com/core/video/iframe*
// ==/UserScript==
document.querySelector("figure").style.zoom = 2;
Save that as myscript.user.js. Open up chrome://extensions and drag that file onto the page. The userscript will have a higher privilege and can access the page.

One way to edit cross-origin domains in an iframe is to load them via the server (PHP) and modify the html by adding a base tag: <base href='http://www.espn.com'/> It's no guarantee that they will let you load all the elements as html and still render the page properly but can work in some cases and is worth the try.
A very simple iframe-loader.php would look like this:
<?php
error_reporting(0);
$url = $_REQUEST['url'];
$html = file_get_contents($url);
$dom = new domDocument;
$dom->strictErrorChecking = false;
$dom->recover = true;
$dom->loadHTML($html);
//Add base tag
$head = $dom->getElementsByTagName('head')->item(0);
$base = $dom->createElement('base');
$base->setAttribute('href',$url);
if ($head->hasChildNodes()) {
$head->insertBefore($base,$head->firstChild);
} else {
$head->appendChild($base);
}
//Print result
echo $dom->saveHTML();
DEMO
Then you load a url by going to /iframe-loader.php?url=http://www.espn.com/core/video/iframe?id=21588864...
Good Luck!

Related

Cannot get reference to one page from another

I am working on a web app that needs to have two parts. The one is a controller and the other is a display. Something like Google Slides in presentation mode. The controller has a button to launch the display:
<script language="JavaScript">
function OpenMain()
{
var MainPage = window.open("TheUltraSignalLite.html");
TimerIMG = MainPage.document.getElementById("TimerIMG");
TimerIMG.src = "TM-Full-Blue.jpg";
}
</Script>
The call to window.open seems to return null. I have tried Chrome, Edge, Firefox, and Opera and they all have the result. These are all local files for now, but I might put in on a web server someday. I have seen some answers that want you to turn off security, but I cannot ask everyone who uses this app to turn off security. How do I get a valid reference to the display window?
Edit 1:
Yes, window.open from the local disk does cause a CORS restriction.
I tried this where both files are in the same AWS S3 Bucket, so the CORS should not be an issue. But I still get a null on the window.open. If I put a breakpoint on the first line, then everything worked. If I split the open and the rest of the code into two functions with two buttons, it works. So it looks like I have to find a way to run the open in an async way.
Edit 2
My solution to keep it simple was to put the window.open in the OnLoad event. This opens the child window and allows it to fully render and the value of MainPage is ready to use. (I changed the MainPage to a global variable.) I still have to run it from some type of web server, rather than loacl file, but that is not a big deal.
If you are not allowed to access the new window content, then the problem you are encountering is a basic security feature of web browsers. Citing mdn:
The returned reference can be used to access properties and methods of the new window as long as it complies with Same-origin policy security requirements
To read more about Same-origin policy
If your new window respects the Same-origin policy, then you can access the content of the new window with for example:
// Open index.html from the current origin
const newWindow = window.open('index.html')
const h1 = newWindow.document.querySelector('h1')
If you want to avoid asking users for pop-up permission, then you should probably use a link instead of a pop-up.

Security concerns with same origin iframes [duplicate]

I am planning to create an open source education web app where people can add and edit the content (a bit like Wikipedia).
However I wish to add another feature that allows the user to add their own interactive content using JavaScript. (similar how JSFiddle does it)
What are the security concerns in doing this?
Optional question: How can these issues be overcome?
Yes you could use HTML5 Sandbox to only load user scripts in an IFrame.
You should only host user content from a different domain than your main site. This will prevent any XSS attack if an attacker convinces a user to visit the page directly (outside of the sandbox). e.g. if your site is www.example.com you could use the following code to display the sandboxed IFrame (note .org rather than .com, which is an entirely different domain):
<iframe src="https://www.example.org/show_user_script.aspx?id=123" sandbox="allow-scripts"></iframe>
This will allow scripts, but forms and navigation outside of the IFrame will be prevented. Note that this approach could still risk a user hosting a phishing form to capture credentials. You should make sure that the boundaries between your site and the user content are clear within the user interface. Even though we haven't specified allow-forms, this only prevents a form from being submitted directly, it does not prevent form elements and JavaScript event handlers from sending any data to an external domain.
The HTML5 Security Cheat Sheet guidance on OWASP states this is the purpose of the sandbox:
Use the sandbox attribute of an iframe for untrusted content
You should test whether sandbox is supported first, before rendering the IFrame:
<iframe src="/blank.htm" sandbox="allow-scripts" id="foo"></iframe>
var sandboxSupported = "sandbox" in document.createElement("iframe");
if (sandboxSupported) {
document.getElementById('foo').setAttribute('src', 'https://www.example.org/show_user_script.aspx?id=123');
}
else
{
// Not safe to display IFrame
}
It is safer to do it this way by dynamically changing the src rather than redirecting away if sandboxSupported is false because then the iframe will not accidentally be rendered if the redirect doesn't happen in time.
As a simpler alternative, without the need to check whether the sandbox is supported, you can use the srcdoc IFrame attribute to generate the sandboxed content, making sure that all content is HTML encoded:
e.g.
<html><head></head><body>This could be unsafe</body></html>
would be rendered as
<iframe srcdoc="<html><head></head><body>This could be unsafe</body></html>" sandbox="allow-scripts"></iframe>
Or you could construct a data blob object, being careful to HTML encode again:
<body data-userdoc="<html><head></head><body>This could be unsafe</body></html>">
<script>
var unsafeDoc = new Blob([document.body.dataset.userdoc], {type: 'text/html'});
var iframe = document.createElement('iframe');
iframe.src = window.URL.createObjectURL(unsafeDoc);
iframe.sandbox = 'allow-scripts';
</script>
Of course you could also set the unsafeDoc variable from a JSON data source. It is not recommended to load an HTML file, as this has the same problem of it having to be from an external domain, as the attacker could just entice the user to load that directly.
Also, please don't be tempted to write user content into a script block directly. As shown above, data attributes is the safe way to do this, as long as correct HTML encoding is carried out on the user data as it is output server-side.
In these cases you can leave src as blank.html as older browsers that do not support srcdoc will simply load that URL.
As #Snowburnt touches upon, there is nothing stopping a user script from redirecting a user to a site where a drive-by download occurs, but this approach, assuming a user is up to date on patches, and there are no zero day vulnerabilities, this is a safe approach because it protects its end users and their data on your site via the same origin policy.
One big issue is cross-site scripting where users add code that tells the browser to open and run code from other sites. Say they add something that creates an iFrame or a hidden iFrame pointing to a site and starts downloading malicious code.
There's no simple way around it (thanks to Bergi in the comments) to make sure no elements are created and no ajax calls are made.
I've been a member of sites that provided this functionality, but for those sites I paid for my own space so any vulnerabilities I add are inconveniencing my own clients, in that case it's a little more okay to let that slip by since it's not a security leak for everyone.
One way around this is to create customizable controls for the users to use to add interactivity. The plus is that you control the javascript being added, the minus is that your user base will have to request and then wait for you to create them.

Remove target attribute in iframe link

I have an iframe on one of my pages that shows content on an external site (vendor product). All works well except a few links that have target="_main" in them. These links open in a new tab. What I need to do is strip the target attribute from all links within the iframe so all links stay within the iframe rather than opening a new window or tab.
It seems like there should be a simple javascript solution to this.
If I can't get this to work in an iframe then I will be forced to re-create all the content on my site which would be very painful..... to say the least.
Any help???
You need access to the external site's codebase in order to dynamically fix this. What you want to do in the external site's codebase is to check if the sites is within an iframe. If it is within an iframe then run a function to remove all target attributes on links.
// vendors product page
if ( self !== top ){
$('a').removeAttr('target');
} // else do nothing
self !== top is the same as saying if my site isn't the top most window then return true.
Not directly that I am aware of.
However, if you have access to a scripting language (like PHP or ASP) on your site you can read your vendors' page directly from your server, do a find & replace on it & then render that onto your site; either in an iframe or however else you want.
Edit
There are many ways to do this, depending on how much control you have over you PHP config. Have a look at these resources & see if you can figure out what to do. If not I would suggest you start a new question specifically focused on what it is you are struggling with.
http://php.net/manual/en/function.file-get-contents.php With this method you have to be aware of the tip on the page:
A URL can be used as a filename with this function if the fopen wrappers have been enabled. See fopen() for more details on how to specify the filename. See the Supported Protocols and Wrappers for links to information about what abilities the various wrappers have, notes on their usage, and information on any predefined variables they may provide.
http://php.net/manual/en/function.fsockopen.php Again, be aware of the warning & notes.
http://php.net/manual/en/book.curl.php
I personally have written a class that uses fsockopen because it is the most flexible for my needs but usually file_get_contents does the trick because it is the simplest to set up out of the 3 options, if you have the right wrappers configured & you don't need to start working with SSL or funny protocols. I stay away from CURL because you have to install a library in order for it to work. I prefer my code to be portable for standard installs.
Some useful links that might help:
PHP readfile from external server
Possible Example
$vendorUrl = isset( $_REQUEST['vendor'] ) ? $_REQUEST['vendor'] : 'www.default-vendor.com';
$iframeContents = file_get_contents("http://$vendorUrl", false);
exit str_replace( 'target="_main"', '', $iframeContents );
Then you just have point your iframe at whatever page you save this script in on your server & include ?vender=www.vendor-url.com as the query string.
How about giving your own iframe the name _main?
<iframe name="_main" ...
The other links should then open in that iframe too.
Regards, Max

Reading document.links from an IFrame

EDIT:
Just a quick mention as to the nature of this program. The purpose of this program is for web inventory. Drawing different links and other content into a type of hierarchy. What I'm having trouble with is pulling a list of links from a webpage within an IFrame.
I get the feeling this one is gonna bite me hard. (other posts indicate relevance to xss and domain controls)
I'm just trying something with javascript and Iframes. Basically I have a panel with an IFrame inside that goes to whatever website you want it to. I'm trying to generate a list of links from the webpage within the Iframe. Its strictly read only.
Yet I keep coming up against the permission denied problem.
I understand this is there to stop cross site scripting attacks and the resolution seems to be to set the document domain to the host site.
JavaScript permission denied. How to allow cross domain scripting between trusted domains?
However I dont think this will work if I'm trying to go from site to site.
Heres the code I have so far, pretty simple:
function getFrameLinks()
{
/* You can all ignore this. This is here because there is a frame within a frame. It should have no effect ont he program. Just start reading from 'contentFrameElement'*/
//ignore this
var functionFrameElem = document.getElementById("function-IFrame");
console.log("element by id parent frame ");
console.log(functionFrameElem);
var functionFrameData = functionFrameElem.contentDocument;
console.log("Element data");
console.log(functionFrameData);
//get the content and turn it into a doc
var contentFrameElem = functionFrameData.getElementById("content-Frame")
console.log(contentFrameElem);
var contentFrameData = contentFrameElem.contentDocument;
console.log(contentFrameData);
//get the links
//var contentFrameLinks = contentFrameData.links;
var contentFrameLinks = contentFrameData.getElementsByTagName('a');
Goal: OK so due to this being illegal and very similar to XSS. Perhaps someone could point out a solution as to how to locally store the document. I dont seem to have any problems accessing document.links with internal pages in the frame.
Possibly some sort of temp database of cache. The simpler the solution the better.
If you want to read it just for your self and in your browser, you can write a simple proxy with php in your server. the most simple code:
<?php /* proxy.php */ readfile($_GET['url']); ?>
now set your iframe src to your proxy file:
<iframe src="http://localhost/proxy.php?url=http://www.google.com"
id="function-IFrame"></iframe>
now you can access the iframe content from your (local) server.
if you want set the url with a program remember to encode the url (urlencode in php or encodeURIComponent in js)
Here is a bookmarklet you can run on any page (assuming the links are not in an iframe)
javascript:var x=function(){var lnks=document.links,list=[];for (var i=0,n=lnks.length;i<n;i++) {var href = lnks[i].href; list.push(href)};if (list.length>0) { var w=window.open('','_blank');w.document.write(list.length+' links found<br/><ul><li>'+list.sort().join('</li><li>')+'</ul>');w.document.close()}};void(x());
the other way is for you (on Windows) to save your HTML with extension .HTA
Then you can grab whatever lives in the iFrame
You might be interested in using the YQL (Yahoo Query Language) to retrieve filtered results from remote urls..
example of retrieving all the links from the yahoo.com domain

How to get page source of page at another domain (in Javascript!)

I am trying to get the source page of a webpage on a different domain. I know this is easily done with PHP for example but I would like to do it in Javascript because I am getting results from a page and if I use a server-side language, the original website will block the calls since they come from the same IP. However, if the calls are done on the client side, it is like the user request the results each time (different user, different IP, no original site blocking me). Is there a way to do that (even if not in Javascript but client-side).
To clarify the code I want will be applied to an HTML page so I can get the results, style them, add/delete, etc then display them to the user.
Thank you.
Modern browsers support cross-domain AJAX calls but the target site has to allow them by using special headers in the reply. Apart from that, there is no pure Javascript solution AFAIK.
Could you use an iframe? You wont have direct access to the markup to due to cross-domain restrictions, but you can still display the third-party page to the user...
window.onload = function() {
var i = document.createElement("IFRAME");
i.setAttribute("name", "ID_HERE");
i.setAttribute("id", "ID_HERE");
i.setAttribute("src", "URL_HERE");
i.style.maxHeight = "300px";
i.style.width = "100%";
document.body.appendChild(i);
}
On Windows you can use HTA
An HTA can access anything crossdomain in an iframe for example

Categories