As part of some XSS research I'm doing, I'm trying to spawn an iframe with a changed form action and then close the iframe after the victim has submitted their details. I have the below code so far:
<body onload="iframeEdit()">
<script>
function deleteIframe() {
var iframe = document.getElementById("myframe");
iframe.parentNode.removeChild(iframe);
}
function iframeEdit() {
var iframe = document.getElementById("myframe");
var innerDoc = iframe.contentDocument || iframe.contentWindow.document;
var form = innerDoc.getElementsByTagName("form");
form[0].action = "http://127.0.0.1/new/page.php";
form[0].setAttribute("onSubmit", "deleteIframe()");
}
</script>
<iframe id="myframe" src="http://127.0.0.1/iframe/page.php" height="250" width="300">
That code still posts the form details to the php page; however, it fails to close the iframe afterwards. I know the iframe delete code works, as if I try it on its own in it works as it should. So it's either to do with the logic flow of the script, or the setAttribute line isn't working as it should. Can anyone shed some light on where I'm going wrong? Thanks!
There may be a better way to do this, but a work around I found was to pause the deleteIframe function, via setTimeout(). I found as little as 5 milliseconds was enough for the form details to be successfully posted :)
function deleteIframeTimer(){
var t = setTimeout("deleteIframe()", 5);
}
function deleteIframe() {
var iframe = parent.document.getElementById("myframe");
iframe.parentNode.removeChild(iframe);
}
Many thanks to Jason for the parenttip!
This is just a guess without running your code
form[0].setAttribute("onSubmit", "parent.deleteIframe()");
My guess is that the iframe cannot access the parent window directly, so you'll need the parent
Related
I have an iframe of a certain page from a site that I'm using, but I don't want all the parts of that page to be displayed with the iframe. Particularly, there's a navigation sidebar on the page that I don't want to be in the iframe. I'm trying to achieve this with the javascript seen below, but I can't quite figure it out.
<iframe width="800" height="800" src="scores/new?site_id=193">
<script>
var element = document.getElementById("sidebar-wrapper");
element.parentNode.removeChild(element);
</script>
</iframe>
For security reasons you can't run javascript through iframes. There are some exceptions if you're on the same domain but for the most part you should really avoid it.
If the iframe isn't a site you can control then there's pretty much nothing you can do. If you do control the other site and it's a different domain you might be able to work with the postMessage functions.
Edit: Check out the docs that Mozilla has up here https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage
You'd need to create a listener on the inside that handles a message and hides your sidebar. Then on the parent send a message to the iframe to trigger that function.
Parent:
var iframe = document.getElementById('#iframeID');
iframe.contentWindow.postMessage('iframeTrigger');
Iframe:
window.addEventListener('iframeTrigger', hideSidebar);
function hideSidebar() {
//do stuff
}
You can insert a control in the iframed page
//inside the iframed page
var iframe = (function() {
try {
return window.self !== window.top;
} catch (e) {
return true;
}
})();
if(iframe === true) {
var element = document.getElementById("sidebar-wrapper");
element.parentNode.removeChild(element);
}
Hope this could suit your need.
This should work theoretically, and it works in console. But this doesn't work in the HTML, although you are trying it from the same domain, because of security reasons. I just wanted to tell my view and I tried this:
<iframe src="http://output.jsbin.com/figujeyiyo" frameborder="0" id="ifrm">
Sorry, iframes not supported.
</iframe>
<script>
console.log(document.getElementById("ifrm").contentDocument.documentElement.getElementsByTagName("div"));
e = document.getElementById("ifrm").contentDocument.documentElement.getElementsByTagName("div")[0];
console.log(e);
e.parentNode.removeChild(element);
</script>
You need to execute the code when the page loads, you can do it like this:
document.addEventListener('DOMContentLoaded', function() {
var element = document.getElementById("sidebar-wrapper");
element.parentNode.removeChild(element);
});
Some websites have code to "break out" of IFRAME enclosures, meaning that if a page A is loaded as an IFRAME inside an parent page P some Javascript in A redirects the outer window to A.
Typically this Javascript looks something like this:
<script type="text/javascript">
if (top.location.href != self.location.href)
top.location.href = self.location.href;
</script>
My question is: As the author of the parent page P and not being the author of the inner page A, how can I prevent A from doing this break-out?
P.S. It seems to me like it ought to be a cross-site security violation, but it isn't.
With HTML5 the iframe sandbox attribute was added. At the time of writing this works on Chrome, Safari, Firefox and recent versions of IE and Opera but does pretty much what you want:
<iframe src="url" sandbox="allow-forms allow-scripts"></iframe>
If you want to allow top-level redirects specify sandbox="allow-top-navigation".
I use the sandbox attribute on the iframe element:
allow-forms allow form submission
allow-popups allows popups
allow-pointer-lock allows pointer lock
allow-same-origin allows the document to maintain its origin
allow-scripts allows JavaScript execution, and also allows features to trigger automatically
allow-top-navigation allows the document to break out of the frame by navigating the top-level window
Top navigation is what you want to prevent, so leave that out and it will not be allowed. Anything left out will be blocked
ex.
<iframe sandbox="allow-same-origin allow-scripts allow-popups allow-forms" src="http://www.example.com"</iframe>
Try using the onbeforeunload property, which will let the user choose whether he wants to navigate away from the page.
Example: https://developer.mozilla.org/en-US/docs/Web/API/Window.onbeforeunload
In HTML5 you can use sandbox property. Please see Pankrat's answer below.
http://www.html5rocks.com/en/tutorials/security/sandboxed-iframes/
After reading the w3.org spec. I found the sandbox property.
You can set sandbox="", which prevents the iframe from redirecting. That being said it won't redirect the iframe either. You will lose the click essentially.
Example here: http://jsfiddle.net/ppkzS/1/
Example without sandbox: http://jsfiddle.net/ppkzS/
I know it has been a long time since question was done but here is my improved version it will wait 500ms for any subsequent call only when the iframe is loaded.
<script type="text/javasript">
var prevent_bust = false ;
var from_loading_204 = false;
var frame_loading = false;
var prevent_bust_timer = 0;
var primer = true;
window.onbeforeunload = function(event) {
prevent_bust = !from_loading_204 && frame_loading;
if(from_loading_204)from_loading_204 = false;
if(prevent_bust){
prevent_bust_timer=500;
}
}
function frameLoad(){
if(!primer){
from_loading_204 = true;
window.top.location = '/?204';
prevent_bust = false;
frame_loading = true;
prevent_bust_timer=1000;
}else{
primer = false;
}
}
setInterval(function() {
if (prevent_bust_timer>0) {
if(prevent_bust){
from_loading_204 = true;
window.top.location = '/?204';
prevent_bust = false;
}else if(prevent_bust_timer == 1){
frame_loading = false;
prevent_bust = false;
from_loading_204 = false;
prevent_bust_timer == 0;
}
}
prevent_bust_timer--;
if(prevent_bust_timer==-100) {
prevent_bust_timer = 0;
}
}, 1);
</script>
and onload="frameLoad()" and onreadystatechange="frameLoad();" must be added to the frame or iframe.
Since the page you load inside the iframe can execute the "break out" code with a setInterval, onbeforeunload might not be that practical, since it could flud the user with 'Are you sure you want to leave?' dialogs.
There is also the iframe security attribute which only works on IE & Opera
:(
In my case I want the user to visit the inner page so that server will see their ip as a visitor. If I use the php proxy technique I think that the inner page will see my server ip as a visitor so it is not good. The only solution I got so far is wilth onbeforeunload.
Put this on your page:
<script type="text/javascript">
window.onbeforeunload = function () {
return "This will end your session";
}
</script>
This works both in firefox and ie, thats what I tested for.
you will find versions using something like evt.return(whatever) crap... that doesn't work in firefox.
try:
<iframe sandbox=" "></iframe>
By doing so you'd be able to control any action of the framed page, which you cannot. Same-domain origin policy applies.
Edit: Just found out this is a chrome problem, the code works fine in firefox
I have an iframe on a webpage that shows a book formatted as html. I would like to insert some javascript within this iframe to make the book more dynamic (e.g. click on sentences, show animations etc). The iframe content is in the same domain as the parent page.
I can insert the javascript into the iframe but get an error calling a function in the inserted javascript. I've described the different bits of code below:
My parent page javascript is:
function iframeLoaded()
{
var iFrameID = document.getElementById('preview-iframe');
var jsLink = iFrameID.contentDocument.createElement("script");
jsLink.src="/tests/iframeAPI.js";
jsLink.type = 'text/javascript';
iFrameID.contentDocument.head.appendChild(jsLink);
iFrameID.contentWindow.initialiseApi()
}
and the html containing the iframe is:
<iframe id="preview-iframe" width="640" height="240" frameborder="0" src="./testpage.htm" onload="iframeLoaded()" scrolling="no"></iframe>
The contents of iframeAPI.js is:
window.initialiseApi = function() { alert("Hello world") }
Looking at the iFrame's html in the browser shows that the iFrameAPI.js tag is inserted ok into the iframe head, but I don't get the alert popup when the page is loaded. The error appears on the following line:
iFrameID.contentWindow.initialiseApi()
Uncaught TypeError: Object [object Window] has no method 'initialiseApi'
However I can run this line in the browser's javascript console and the alert popup works fine.
Any help would be much appreciated.
Thanks,
Brian
Edit: I've just tried with an onload event to make sure the page is loaded and I still have the problem:
My parent page javascript is now :
function iframeLoaded()
{
var iFrameID = document.getElementById('preview-iframe');
var jsLink = iFrameID.contentDocument.createElement("script");
jsLink.src="/tests/iframeAPI.js";
jsLink.type = 'text/javascript';
iFrameID.contentDocument.head.appendChild(jsLink);
jsLink.onLoad= iFrameLoaded();
}
function iFrameLoaded()
{
alert("Iframe loaded"); // Alert works ok
var iFrameID = document.getElementById('preview-iframe');
iFrameID.contentWindow.initialiseApi(); // Same error message on this line
}
It sounds like you are trying to use the function before the content has loaded.
try this instead:
var t = setTimeout(iFrameID.contentWindow.initialiseApi(),500);
This will wait half a second before trying the function which should give the page tiem to load. Delay times are given in milliseconds.
An even better approach is to try using Jquery and its ready() method but this requires the jquery library to be loaded as well. Its well worth it though in my opinion, see http://api.jquery.com/ready/.
You would try something like:
$("body",iFrameID.contentWindow.document).ready(iFrameID.contentWindow.initialiseApi())
You're executing it right away without giving the script a chance to load. Hook up an onload event to your script block and run your main function then.
Try, in the page included in the iFrame, accessing the main page by doing something like:
window.parent.xyz = something;
Where something is what you want exposed to the main page. Could be a function or an object of functions. Now in the main page you can just do:
something(); // or something.somefunction();
You could also send window references, I think, but I have not tried that.
The easiest way is to call the initialiseApi function in the iframeAPI.js itself as it will be called as soon as it's loaded. The iframeAPI.js could look like that:
function initialiseApi() {
alert("Hello world");
}
initialiseApi();
There is no callback or timeout needed.
I want to access the currently loaded document of an iframe and link that document to another iframe, for this I tried:
$("#if1").attr("src", $("#if2").attr("src"));
But this loads the document again. I want to access the document already loaded in #if1. How can I do this?
$("#if1").attr("src", $("#if2").attr("src"));
But this loads the document again.
Err, yeah, that's what you are doing: you are setting if1's src to if2's src. That's why it reloads the iFrame... If you exchange if1 and if2 in your code it might do what you're trying to do -- if I managed to understand you.
Check out this running demo: http://jsfiddle.net/aymansafadi/BanTV/5/show/
The key part you might be interested is:
$('#swap').on('click', function() {
var iframe1 = $('#if1')[0].contentWindow.location.href;
var iframe2 = $('#if2')[0].contentWindow.location.href;
$('#if1')[0].contentWindow.location.href = iframe2;
$('#if2')[0].contentWindow.location.href = iframe1;
});
NOTE: This, and anything else you you try, will only work if both iframes are under the same domain as the parent window.
You can also use .src('attr') to set the URL, but not get the current URL.Demo: http://jsfiddle.net/aymansafadi/BanTV/7/show/
$('#swap').on('click', function() {
var iframe1 = $('#if1')[0].contentWindow.location.href;
var iframe2 = $('#if2')[0].contentWindow.location.href;
$('#if1').attr('src', iframe2);
$('#if2').attr('src', iframe1);
});
This is my code
<script>
var body = "dddddd"
var script = "<script>window.print();</scr'+'ipt>";
var newWin = $("#printf")[0].contentWindow.document;
newWin.open();
newWin.close();
$("body",newWin).append(body+script);
</script>
<iframe id="printf"></iframe>
This works but it prints the parent page, how do I get it to print just the iframe?
I would not expect that to work
try instead
window.frames["printf"].focus();
window.frames["printf"].print();
and use
<iframe id="printf" name="printf"></iframe>
Alternatively try good old
var newWin = window.frames["printf"];
newWin.document.write('<body onload="window.print()">dddd</body>');
newWin.document.close();
if jQuery cannot hack it
Live Demo
document.getElementById("printf").contentWindow.print();
Same origin policy applies.
Easy way (tested on ie7+, firefox, Chrome,safari ) would be this
//id is the id of the iframe
function printFrame(id) {
var frm = document.getElementById(id).contentWindow;
frm.focus();// focus on contentWindow is needed on some ie versions
frm.print();
return false;
}
an alternate option, which may or may not be suitable, but cleaner if it is:
If you always want to just print the iframe from the page, you can have a separate "#media print{}" stylesheet that hides everything besides the iframe. Then you can just print the page normally.
You can use this command:
document.getElementById('iframeid').contentWindow.print();
This command basically is the same as window.print(), but as the window we would like to print is in the iframe, we first need to obtain an instance of that window as a javascript object.
So, in reference to that iframe, we first obtain the iframe by using it's id, and then it's contentWindow returns a window(DOM) object. So, we are able to directly use the window.print() function on this object.
I had issues with all of the above solutions in IE8, have found a decent workaround that is tested in IE 8+9, Chrome, Safari and Firefox. For my situation i needed to print a report that was generated dynamically:
// create content of iframe
var content = '<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">'+
'<head><link href="/css/print.css" media="all" rel="stylesheet" type="text/css"></head>'+
'<body>(rest of body content)'+
'<script type="text/javascript">function printPage() { window.focus(); window.print();return; }</script>'+
'</body></html>';
Note the printPage() javascript method before the body close tag.
Next create the iframe and append it to the parent body so its contentWindow is available:
var newIframe = document.createElement('iframe');
newIframe.width = '0';
newIframe.height = '0';
newIframe.src = 'about:blank';
document.body.appendChild(newIframe);
Next set the content:
newIframe.contentWindow.contents = content;
newIframe.src = 'javascript:window["contents"]';
Here we are setting the dynamic content variable to the iframe's window object then invoking it via the javascript: scheme.
Finally to print; focus the iframe and call the javascript printPage() function within the iframe content:
newIframe.focus();
setTimeout(function() {
newIframe.contentWindow.printPage();
}, 200);
return;
The setTimeout is not necessarily needed, however if you're loading large amounts of content i found Chrome occasionally failed to print without it so this step is recommended. The alternative is to wrap 'newIframe.contentWindow.printPage();' in a try catch and place the setTimeout wrapped version in the catch block.
Hope this helps someone as i spent a lot of time finding a solution that worked well across multiple browsers. Thanks to SpareCycles.
EDIT:
Instead of using setTimeout to call the printPage function use the following:
newIframe.onload = function() {
newIframe.contentWindow.printPage();
}
At this time, there is no need for the script tag inside the iframe. This works for me (tested in Chrome, Firefox, IE11 and node-webkit 0.12):
<script>
window.onload = function() {
var body = 'dddddd';
var newWin = document.getElementById('printf').contentWindow;
newWin.document.write(body);
newWin.document.close(); //important!
newWin.focus(); //IE fix
newWin.print();
}
</script>
<iframe id="printf"></iframe>
Thanks to all answers, save my day.
If you are setting the contents of IFrame using javascript document.write() then you must close the document by newWin.document.close(); otherwise the following code will not work and print will print the contents of whole page instead of only the IFrame contents.
var frm = document.getElementById(id).contentWindow;
frm.focus();// focus on contentWindow is needed on some ie versions
frm.print();
I was stuck trying to implement this in typescript, all of the above would not work. I had to first cast the element in order for typescript to have access to the contentWindow.
let iframe = document.getElementById('frameId') as HTMLIFrameElement;
iframe.contentWindow.print();
Use this code for IE9 and above:
window.frames["printf"].focus();
window.frames["printf"].print();
For IE8:
window.frames[0].focus();
window.frames[0].print();
I am wondering what's your purpose of doing the iframe print.
I met a similar problem a moment ago: use chrome's print preview to generate a PDF file of a iframe.
Finally I solved my problem with a trick:
$('#print').click(function() {
$('#noniframe').hide(); // hide other elements
window.print(); // now, only the iframe left
$('#noniframe').show(); // show other elements again.
});