I have this code:
$( "#drawingSurface" ).mousedown(function(event) {
$('.infoText').text('Started! Please Wait..');
compilation(); // this takes a long time.
}
Now no matter what I do, $('.infoText').text('Started! Please Wait..'); will just not execute. The element is there, it is annoying because compilation takes ages to finish and when it is done then the text shows up. I want the text to SHOW up as in the order that I have written things.
It's executing, but while compilation is running, it prevents the browser from updating the display of the page.
You can fix that by introducing a very brief delay between the text update and compilation:
$( "#drawingSurface" ).mousedown(function(event) {
$('.infoText').text('Started! Please Wait..');
setTimeout(compilation, 50);
});
That way the browser has a chance to show the change before blocking on the long-running compilation. (0 usually works on Chrome, but Firefox typically needs about 50. YMMV.)
If you can, consider moving compilation to a web worker (spec | MDN) so you don't have to block the main UI thread at all.
Seems like the DOM update does not behave synchronously (edit: not exactly, see comments), so it begins executing your function (compilation()) before the text in the div changes. As a workaround, you could add it to a timeout such as the following
$( () => {
$( "#drawingSurface" ).mousedown(function(event) {
console.log('hi');
$('.infoText').text('Started! Please Wait..');
setTimeout(doWork, 1);
});
});
function doWork() {
let i = 0;
while (i < 1e3) {
console.log('waiting');
i++
}
$('.infoText').text('Done.');
console.log('finished');
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="drawingSurface">
Click me
</div>
<div class="infoText">
text
</div>
Alternatively, you could move '$('.infoText').text('Started! Please Wait..');' to be inside the compilation function.
I came across a situation were a button event handler calls a function, that may take a couple seconds to complete depending on the input. Once the function completes, the output will show up in a grid.
The function is completely client side. Right before the function is running I add a css class to the grid wrapper div that basically just shows a 'loading' gif/animation.
This works fine in Chrome, but not in Firefox and IE 11.
Below is an oversimplified version of how I achieve this with javascript setTimeout 0.
$('#calc').on('click', function(){
$('#container').addClass('loading');
calculate(10, function(res){
$('#result').text(res);
$('#container').removeClass('loading');
});
});
//represents my long running function
function fib(n) {
if(n<2) {
return n;
}
return fib(n-2) + fib(n-1);
}
//will be called by click handler
function calculate(n,cb) {
setTimeout(function(){
var result = fib(n);
return cb(result);
},0)
}
As you can see I use setTimeout 0 in calculate(n,cb) to give the browser the ability to show the 'loading' animation before the function starts and then remove it when it is done.
However, this does not work in Firefox.
What are some other options for me to achieve what I am trying to do?
I am using jQuery here, but the actual project I am working on is using Angular5. But the idea should be the same.
Here is a jsFiddle to show what I am trying to do. Using the loading animation by Mattln4D (thanks)
https://jsfiddle.net/alabianc/qL5zggh7/
If you want to see some actual good result, run it with 40 as an input in calculate, but no more than that!
I appreciate any help!
I think if you set the timeout = 0, it is so fast to browser can show the loading animation. When I try to change timeout = 10 or 100, I can see the loading animation show on both of chrome, ff.
Let's say you don't want other sites to "frame" your site in an <iframe>:
<iframe src="http://example.org"></iframe>
So you insert anti-framing, frame busting JavaScript into all your pages:
/* break us out of any containing iframes */
if (top != self) { top.location.replace(self.location.href); }
Excellent! Now you "bust" or break out of any containing iframe automatically. Except for one small problem.
As it turns out, your frame-busting code can be busted, as shown here:
<script type="text/javascript">
var prevent_bust = 0
window.onbeforeunload = function() { prevent_bust++ }
setInterval(function() {
if (prevent_bust > 0) {
prevent_bust -= 2
window.top.location = 'http://example.org/page-which-responds-with-204'
}
}, 1)
</script>
This code does the following:
increments a counter every time the browser attempts to navigate away from the current page, via the window.onbeforeunload event handler
sets up a timer that fires every millisecond via setInterval(), and if it sees the counter incremented, changes the current location to a server of the attacker's control
that server serves up a page with HTTP status code 204, which does not cause the browser to navigate anywhere
My question is -- and this is more of a JavaScript puzzle than an actual problem -- how can you defeat the frame-busting buster?
I had a few thoughts, but nothing worked in my testing:
attempting to clear the onbeforeunload event via onbeforeunload = null had no effect
adding an alert() stopped the process let the user know it was happening, but did not interfere with the code in any way; clicking OK lets the busting continue as normal
I can't think of any way to clear the setInterval() timer
I'm not much of a JavaScript programmer, so here's my challenge to you: hey buster, can you bust the frame-busting buster?
FWIW, most current browsers support the X-Frame-Options: deny directive, which works even when script is disabled.
IE8:
http://blogs.msdn.com/ie/archive/2009/01/27/ie8-security-part-vii-clickjacking-defenses.aspx
Firefox (3.6.9)
https://bugzilla.mozilla.org/show_bug.cgi?id=475530
https://developer.mozilla.org/en/The_X-FRAME-OPTIONS_response_header
Chrome/Webkit
http://blog.chromium.org/2010/01/security-in-depth-new-security-features.html
http://trac.webkit.org/changeset/42333
I'm not sure if this is viable or not - but if you can't break the frame, why not just display a warning. For example, If your page isn't the "top page" create a setInterval method that tries to break the frame. If after 3 or 4 tries your page still isn't the top page - create a div element that covers the whole page (modal box) with a message and a link like...
You are viewing this page in a unauthorized frame window - (Blah blah... potential security issue)
click this link to fix this problem
Not the best, but I don't see any way they could script their way out of that.
We have used the following approach in one of our websites from http://seclab.stanford.edu/websec/framebusting/framebust.pdf
<style>
body {
display : none
}
</style>
<script>
if(self == top) {
document.getElementsByTagName("body")[0].style.display = 'block';
}
else{
top.location = self.location;
}
</script>
Came up with this, and it seems to work at least in Firefox and the Opera browser.
if(top != self) {
top.onbeforeunload = function() {};
top.location.replace(self.location.href);
}
Considering current HTML5 standard that introduced sandbox for iframe, all frame busting codes that provided in this page can be disabled when attacker uses sandbox because it restricts the iframe from following:
allow-forms: Allow form submissions.
allow-popups: Allow opening popup windows.
allow-pointer-lock: Allow access to pointer movement and pointer lock.
allow-same-origin: Allow access to DOM objects when the iframe loaded form same origin
allow-scripts: Allow executing scripts inside iframe
allow-top-navigation: Allow navigation to top level window
Please see: http://www.whatwg.org/specs/web-apps/current-work/multipage/the-iframe-element.html#attr-iframe-sandbox
Now, consider attacker used the following code to host your site in iframe:
<iframe src="URI" sandbox></iframe>
Then, all JavaScript frame busting code will fail.
After checking all frame busing code, only this defense works in all cases:
<style id="antiClickjack">body{display:none !important;}</style>
<script type="text/javascript">
if (self === top) {
var antiClickjack = document.getElementById("antiClickjack");
antiClickjack.parentNode.removeChild(antiClickjack);
} else {
top.location = self.location;
}
</script>
that originally proposed by Gustav Rydstedt, Elie Bursztein, Dan Boneh, and Collin Jackson (2010)
After pondering this for a little while, I believe this will show them who's boss...
if(top != self) {
window.open(location.href, '_top');
}
Using _top as the target parameter for window.open() will launch it in the same window.
As of 2015, you should use CSP2's frame-ancestors directive for this. This is implemented via an HTTP response header.
e.g.
Content-Security-Policy: frame-ancestors 'none'
Of course, not many browsers support CSP2 yet so it is wise to include the old X-Frame-Options header:
X-Frame-Options: DENY
I would advise to include both anyway, otherwise your site would continue to be vulnerable to Clickjacking attacks in old browsers, and of course you would get undesirable framing even without malicious intent. Most browsers do update automatically these days, however you still tend to get corporate users being stuck on old versions of Internet Explorer for legacy application compatibility reasons.
All the proposed solutions directly force a change in the location of the top window. What if a user wants the frame to be there? For example the top frame in the image results of search engines.
I wrote a prototype where by default all inputs (links, forms and input elements) are disabled and/or do nothing when activated.
If a containing frame is detected, the inputs are left disabled and a warning message is shown at the top of the page. The warning message contains a link that will open a safe version of the page in a new window. This prevents the page from being used for clickjacking, while still allowing the user to view the contents in other situations.
If no containing frame is detected, the inputs are enabled.
Here is the code. You need to set the standard HTML attributes to safe values and add additonal attributes that contain the actual values. It probably is incomplete and for full safety additional attributes (I am thinking about event handlers) will probably have to be treated in the same way:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<html>
<head>
<title></title>
<script><!--
function replaceAttributeValuesWithActualOnes( array, attributeName, actualValueAttributeName, additionalProcessor ) {
for ( var elementIndex = 0; elementIndex < array.length; elementIndex += 1 ) {
var element = array[ elementIndex ];
var actualValue = element.getAttribute( actualValueAttributeName );
if ( actualValue != null ) {
element[ attributeName ] = actualValue;
}
if ( additionalProcessor != null ) {
additionalProcessor( element );
}
}
}
function detectFraming() {
if ( top != self ) {
document.getElementById( "framingWarning" ).style.display = "block";
} else {
replaceAttributeValuesWithActualOnes( document.links, "href", "acme:href" );
replaceAttributeValuesWithActualOnes( document.forms, "action", "acme:action", function ( form ) {
replaceAttributeValuesWithActualOnes( form.elements, "disabled", "acme:disabled" );
});
}
}
// -->
</script>
</head>
<body onload="detectFraming()">
<div id="framingWarning" style="display: none; border-style: solid; border-width: 4px; border-color: #F00; padding: 6px; background-color: #FFF; color: #F00;">
<div>
<b>SECURITY WARNING</b>: Acme App is displayed inside another page.
To make sure your data is safe this page has been disabled.<br>
Continue working safely in a new tab/window
</div>
</div>
<p>
Content. Do something
</p>
<form name="acmeForm" action="#" acme:action="real-action.html">
<p>Name: <input type="text" name="name" value="" disabled="disabled" acme:disabled=""></p>
<p><input type="submit" name="save" value="Save" disabled="disabled" acme:disabled=""></p>
</form>
</body>
</html>
if (top != self) {
top.location.replace(location);
location.replace("about:blank"); // want me framed? no way!
}
I'm going to be brave and throw my hat into the ring on this one (ancient as it is), see how many downvotes I can collect.
Here is my attempt, which does seem to work everywhere I have tested it (Chrome20, IE8 and FF14):
(function() {
if (top == self) {
return;
}
setInterval(function() {
top.location.replace(document.location);
setTimeout(function() {
var xhr = new XMLHttpRequest();
xhr.open(
'get',
'http://mysite.tld/page-that-takes-a-while-to-load',
false
);
xhr.send(null);
}, 0);
}, 1);
}());
I placed this code in the <head> and called it from the end of the <body> to ensure my page is rendered before it starts arguing with the malicious code, don't know if this is the best approach, YMMV.
How does it work?
...I hear you ask - well the honest answer is, I don't really know. It took a lot of fudging about to make it work everywhere I was testing, and the exact effect that it has varies slightly depending on where you run it.
Here is the thinking behind it:
Set a function to run at the lowest possible interval. The basic concept behind any of the realistic solutions I have seen is to fill up the scheduler with more events than the frame buster-buster has.
Every time the function fires, try and change the location of the top frame. Fairly obvious requirement.
Also schedule a function to run immediately which will take a long time to complete (thereby blocking the frame buster-buster from interfering with the location change). I chose a synchronous XMLHttpRequest because it's the only mechanism I can think of that doesn't require (or at least ask for) user interaction and doesn't chew up the user's CPU time.
For my http://mysite.tld/page-that-takes-a-while-to-load (the target of the XHR) I used a PHP script that looks like this:
<?php sleep(5);
What happens?
Chrome and Firefox wait the 5 seconds while the XHR completes, then successfully redirect to the framed page's URL.
IE redirects pretty much immediately
Can't you avoid the wait time in Chrome and Firefox?
Apparently not. At first I pointed the XHR to a URL that would return a 404 - this didn't work in Firefox. Then I tried the sleep(5); approach that I eventually landed on for this answer, then I started playing around with the sleep length in various ways. I could find no real pattern to the behaviour, but I did find that if it is too short, specifically Firefox will not play ball (Chrome and IE seem to be fairly well behaved). I don't know what the definition of "too short" is in real terms, but 5 seconds seems to work every time.
If any passing Javascript ninjas want to explain a little better what's going on, why this is (probably) wrong, unreliable, the worst code they've ever seen etc I'll happily listen.
Ok, so we know that were in a frame. So we location.href to another special page with the path as a GET variable. We now explain to the user what is going on and provide a link with a target="_TOP" option. It's simple and would probably work (haven't tested it), but it requires some user interaction. Maybe you could point out the offending site to the user and make a hall of shame of click jackers to your site somewhere.. Just an idea, but it night work..
Well, you can modify the value of the counter, but that is obviously a brittle solution. You can load your content via AJAX after you have determined the site is not within a frame - also not a great solution, but it hopefully avoids firing the on beforeunload event (I am assuming).
Edit: Another idea. If you detect you are in a frame, ask the user to disable javascript, before clicking on a link that takes you to the desired URL (passing a querystring that lets your page know to tell the user that they can re-enable javascript once they are there).
Edit 2: Go nuclear - if you detect you are in a frame, just delete your document body content and print some nasty message.
Edit 3: Can you enumerate the top document and set all functions to null (even anonymous ones)?
If you add an alert right after the buster code, then the alert will stall the javascript thread, and it will let the page load. This is what StackOverflow does, and it busts out of my iframes, even when I use the frame busting buster. It also worked with my simple test page. This has only been tested in Firefox 3.5 and IE7 on windows.
Code:
<script type="text/javascript">
if (top != self){
top.location.replace(self.location.href);
alert("for security reasons bla bla bla");
}
</script>
I think you were almost there. Have you tried:
window.parent.onbeforeunload = null;
window.parent.location.replace(self.location.href);
or, alternatively:
window.parent.prevent_bust = 0;
Note: I didn't actually test this.
If you look at the values returned by setInterval() they are usually single digits, so you can usually disable all such interrupts with a single line of code:
for (var j = 0 ; j < 256 ; ++j) clearInterval(j)
What about calling the buster repeatedly as well? This'll create a race condition, but one may hope that the buster comes out on top:
(function() {
if(top !== self) {
top.location.href = self.location.href;
setTimeout(arguments.callee, 0);
}
})();
I might just have just gotten a way to bust the frame buster buster javascript. Using the getElementsByName in my javascript function, i've set a loop between the frame buster and the actual frame buster buster script.
check this post out. http://www.phcityonweb.com/frame-buster-buster-buster-2426
setInterval and setTimeout create an automatically incrementing interval. Each time setTimeout or setInterval is called, this number goes up by one, so that if you call setTimeout, you'll get the current, highest value.
var currentInterval = 10000;
currentInterval += setTimeout( gotoHREF, 100 );
for( var i = 0; i < currentInterval; i++ ) top.clearInterval( i );
// Include setTimeout to avoid recursive functions.
for( i = 0; i < currentInterval; i++ ) top.clearTimeout( i );
function gotoHREF(){
top.location.href = "http://your.url.here";
}
Since it is almost unheard of for there to be 10000 simultaneous setIntervals and setTimeouts working, and since setTimeout returns "last interval or timeout created + 1", and since top.clearInterval is still accessible, this will defeat the black-hat attacks to frame websites which are described above.
Use htaccess to avoid high-jacking frameset, iframe and any content like images.
RewriteEngine on
RewriteCond %{HTTP_REFERER} !^http://www\.yoursite\.com/ [NC]
RewriteCond %{HTTP_REFERER} !^$
RewriteRule ^(.*)$ /copyrights.html [L]
This will show a copyright page instead of the expected.
You could improve the whole idea by using the postMessage() method to allow some domains to access and display your content while blocking all the others. First, the container-parent must introduce itself by posting a message to the contentWindow of the iframe that is trying to display your page. And your page must be ready to accept messages,
window.addEventListener("message", receiveMessage, false);
function receiveMessage(event) {
// Use event.origin here like
if(event.origin == "https://perhapsyoucantrustthisdomain.com"){
// code here to block/unblock access ... a method like the one in user1646111's post can be good.
}
else{
// code here to block/unblock access ... a method like the one in user1646111's post can be good.
}
}
Finally don't forget to wrap things inside functions that will wait for load events.
I made a simple flashcards HTML application and I experience strange problem with behavior under Android internet browser (default installation) on my Samsung Galaxy Tab2 7.0 tablet. When style of element is changed, such as
$(".question").css('color', '#FFFFFF')
$(".answer").css('color', '#FFFFFF')
$(".tag").css('background-color', '#FFFFFF')
the browser does not make any changes on display immediately. Later in code I am replacing text of containers and calculating sizes to fit text into element. I want this process to be invisible (that's why I want to do this white-on-white). I cannot hide elements, as then calculation would not work.
I have tested this under Windows 7 with Chrome and IE9 and it works great there. So there is some problem with the Android browser. When I put test code alert('debug'); behind the lines above, the Android browser shows message with no changes on colors on elements, but browsers under Windows 7 show message with white-on-white elements as expected.
How can I force Android browser to reflect such style changes immediately? Is there some script function available for that, or some <meta> tag that would fix this? Please advise.
When you say you want to "display style changes immediately" I'm guessing you mean that your script is going to continue to execute and you want the screen to update.
You need to use continuations. Rather than letting your script keep executing you need to yield and continue. You do this by breaking up your code into multiple functions and each piece finishes by setting a timeout for the next piece. Here's a simple example. When this is done with a loop, all the x's appear at once. When using continuations, one x appears at a time.
<html>
<script>
function using_a_loop() {
var e = document.getElementById('spot');
for (var i = 0; i < 1000; ++i) {
e.innerText += ' x';
}
}
function using_continuations(i) {
var e = document.getElementById('spot');
i = i || 0; // start at 0 when i not provided
e.innerText += ' x';
++i;
if (i < 1000) {
setTimeout(function() { using_continuations(i); }, 0);
}
}
</script>
<div id="spot">X marks the spot:</div>
<button onclick="using_a_loop()">use a loop</button>
<button onclick="using_continuations()">use continuations</button>
</html>
I have tried multiple methods in order to show multiple modal dialogues in order prior to finishing processing on the original screen. The modal dialogues would all be kicked off after a form is submitted. They should open in order, because the first modal has info that the second modal needs and so on. All methods I have attempted (with the simplified versions below for now) work fine in IE (and in Mozilla as well), but when I try to test them in Safari they do not work the way I want them to. Here is really the simplified/stipped down verion of what I'm really going for. I basically want to make sure the test.html page loads before the alert goes off. In IE this works the way I would expect it to for both methods below - load the page in the modalcontent div, then show the alert. In firefox, it shows the alert first then the screen changes/reloads. I've tried using the javascript methods setInterval and setTimeout, but in firefox the alert still shows up before the screen refresh. Any idea if there's something I'm missing? Am I approaching this all wrong?
<TABLE><TR>
<TD ALIGN="center" bgcolor="red" onClick="showNonIEModal('test.html');
alert('alert to show up AFTER load');">CLICK ME</TD>
</TR></TABLE>
<div id="modalcontent"></div>
Ajax method:
<SCRIPT>function showNonIEModal(url)
{
var dsp;
var element = document.getElementById("modalcontent");
element.innerHTML = '<p><em>Loading ...</em></p>';
if (window.XMLHttpRequest){
dsp=new XMLHttpRequest();
}
else{
dsp=new ActiveXObject("Microsoft.XMLHTTP");
}
dsp.onreadystatechange=function(){
if (dsp.readyState==4 && dsp.status==200){
element.innerHTML=dsp.responseText;
}
}
dsp.open("GET",url,true);
dsp.send();
}</SCRIPT>
second method:
<SCRIPT>function showNonIEModal(url)
{
var element = document.getElementById("modalcontent");
element.innerHTML='<'+'iframe id="'+frameName+'" name="'+frameName+'" src="'+url+'"
FRAMEBORDER="0" height="500px" width= "600px"><\/iframe>';
}</SCRIPT>
Any ideas? I have spent countless hours on this issue. It seems like this is an issue with Safari. In searching for an answer I have found a lot of responses regarding using JQuery, but that is not an option for me. Any thoughts would be appreciated.
Thanks!
I'm still a little fuzzy on what exactly the order of expected results is, but I think it's:
Click "CLICK ME"
Expect modalcontent div's content to change
Show alert.
If this is correct, here's the problem (I think). You're relying on an ajax request (i.e. something non-synchronous) to complete before running the next line of code. I know IE is working for you, but IE isn't much to go by. What you want is probably something more like this:
<SCRIPT>function showNonIEModal(url, callback)
{
var dsp;
var element = document.getElementById("modalcontent");
element.innerHTML = '<p><em>Loading ...</em></p>';
if (window.XMLHttpRequest){
dsp=new XMLHttpRequest();
}
else{
dsp=new ActiveXObject("Microsoft.XMLHTTP");
}
dsp.onreadystatechange=function(){
if (dsp.readyState==4 && dsp.status==200){
element.innerHTML=dsp.responseText;
callback && callback(); //This is the part I changed
}
}
dsp.open("GET",url,true);
dsp.send();
}</SCRIPT>
Now, when you want to run it..
<TABLE><TR>
<TD ALIGN="center" bgcolor="red" onClick="showNonIEModal('test.html', function () {alert('alert to show up AFTER load')});">CLICK ME</TD>
</TR></TABLE>
<div id="modalcontent"></div>
This will force that alert to wait until the content has been received from the server and processed. Pretty common asynchronous pattern - do X, and then when you're done, run this function which will continue with Y and Z.