Javascript page load delay of specific set of pages - javascript

I want to delay a specific set of webpages using a small greasemonkey script. Basically, if the website being loaded is part of a set of pages, then I want to delay the time the page takes to load. e.g. if the page being loaded is "http://www.a.com/","http://www.a.com/b", etc. then I want to delay the load by 30 secs.

Assuming that Dushara's comment is correct:
"See xkcd.com/862 for what the poster wants. (Hover the mouse over the image to see the reasoning). In fact, I found this question while googling for exactly the same thing."
Then this is not possible in Greasemonkey. The reason is that GM fires after the page has loaded (except for any slow pictures or AJAX calls). So the user would see the page and then it would, say, flash blank for 30 seconds... But, only after quick eyeballs would have seen too much. ;)
Update: This is now possible in Greasemonkey (with the #run-at document-start directive -- Added August 2011). See this answer for an example.
Note that XKCD's creator uses good, old-fashioned willpower to implement his "simple 30-second delay". From his blog entry:
"Lots of people have asked me for the system I used to implement the restriction in the alt-text of today’s comic.
...
I made it a rule that as soon as I finished any task, or got bored with it, I had to power off my computer."
See also: "Browser extension (or other software) to delay page load" -- which now has links to proper extensions that people created for this.

If your reasoning is that you need some time for some elements to load before greasemonkey sees it as loaded, you could always set up an eventlistener that fires off your function when you click instead of on load then when you are ready to have the function fire off you merely have to click on the page somewhere. addEventListener("click", function, false)
If you are merely looking for a way to make it so that pages load automatically after a set amount of time you would have much better luck using imacros.

There exist Greasemonkey scripts that use overlays to do this:
Script #1 (works on one website)
I had tried to modify this and came up with something very rough that works with a list of multiple websites: Script #2. I no longer use the add-on because the script had weird side-effects on certain websites and could affect performance. I'm sure somebody else could do a much better job, but it's out there if you want to try it yourself or try to modify it.
For anybody not familiar with Greasemonkey, it is a Firefox add-on that allows you to modify websites with little snippets of javascript that you can write yourself or install from a library. To use either of these scripts, you of course need to install the Greasemonkey add-on (https://addons.mozilla.org/en-US/firefox/addon/greasemonkey/) (not linked due to a lack of rep - anybody with edit privileges please feel free to link).

As mentioned, GreaseMonkey scripts are executed on DOMContentLoaded, so after the page loads.
But well, in fact you can create a overlay <div> for certain number of seconds and it will have the same effect.
Here is a bit improved version of userscripts linked by #Jonathan (in fact, I wrote it by myself independently ;)
(function()
{
var timeout = 30;
var timeElapsed = timeout;
function hide()
{
document.documentElement.style.overflow = "hidden";
var newdiv = document.createElement('div');
newdiv.id = "leechblocker";
newdiv.style.width = "100%";
newdiv.style.minHeight = "100%";
newdiv.style.position = "fixed";
newdiv.style.top = "0px";
newdiv.style.left = "0px";
newdiv.style.zIndex = 10000;
newdiv.style.backgroundColor = "white";
newdiv.style.display = "block";
newdiv.style.overflow = "hidden";
newdiv.style.textAlign = "center";
newdiv.style.paddingTop = (window.innerHeight/2-10)+"px";
newdiv.innerHTML = "Wait <span id='counter'>"+timeElapsed+"</span> seconds...";
document.body.appendChild(newdiv);
}
function updateCounter()
{
var counter = document.getElementById("counter");
timeElapsed--;
counter.innerHTML = timeElapsed;
}
function unhide()
{
document.documentElement.style.overflow = "auto";
var leechDiv = document.getElementById("leechblocker");
leechDiv.parentNode.removeChild(leechDiv);
}
hide();
window.setInterval(updateCounter,1000);
window.setTimeout(unhide,timeout*1000);
}());

Related

Embedded img doesnt always appear in JavaScript created page

I need to generate an HTML page, with an embedded logo and print it using just JavaScript, no jQuery.
This code works, some of the time. Most times, the image isn't printed, although if you close the print dialog box, the image is then in the generated document.
EDIT
Screen shots - common logo not displayed
Logo displayed
I think what is happening is that the browser hasnt had time to decode the base 64 img before its sent to print.
var player = GetPlayer();
var textEntry1=player.GetVar("Page1");
var textEntry2=player.GetVar("Q2");
var textEntry3=player.GetVar("Page2");
var contents = "<html><head></head><body style='width:650px;padding:20px;'>";
// Logo as base 64 encoded. Its about a 5Kb file. Chopped for clarity
contents+="<img src='data:image/png;base64,iVBOR ... gAAAABJRU5ErkJggg=='>";
contents+="<div style='font-size:26px;font-weight:bold;margin-top:26px;margin-bottom:20px;'>Print Your Answers to PDF or Paper</div>";
contents+="<div style='display:block;border-width:1px';><hr/></div>";
contents+="<div style='font-size:16px;font-weight:bold;'>Question 1</div>";
contents+="<p>"+textEntry1+"</p>";
contents+="<div style='font-size:16px;font-weight:bold;'>"+textEntry2+"</div>";
contents+="<p>"+textEntry3+"</p>";
contents+= "</body></html>";
var myWindow = window.open("","Print","width=810,height=610,scrollbars=1,resizable=1");
myWindow.document.write(contents);
myWindow.print();
I have tried
window.setTimeout(myWindow.print(), 3000);
and
myWindow.setTimeout(myWindow.print(), 3000);
Neither seem to work as the print dialog just appears without the wait.
Also tried myWindow.onload() but that doesn't even open the print dialog.
Thanks
This is a bad practice if you don't need wait 3s: (the bad practice is use setTimeout not the 3s, The time have to be used only when you can not use others events, try to avoid the use)
window.setTimeout(myWindow.print(), 3000);
myWindow.setTimeout(myWindow.print(), 3000);
JS works with some signals, the DOM render is splitted of the rest of execution:
here you can read more about it https://blog.logrocket.com/how-browser-rendering-works-behind-the-scenes-6782b0e8fb10/
Small summary:
Js first execute the full scripts and at the end execute the browse render.
when you use setTimeout js moves these function out of the execution thread, and after the time generate a event for call it.
test some like this:
var myWindow = window.open("","Print","width=810,height=610,scrollbars=1,resizable=1");
myWindow.document.write(contents);
mywindow.document.write('<script type="text/javascript">
window.onload=function() {
mywindow.document.close(); // necessary for IE >= 10
mywindow.focus(); // necessary for IE >= 10*/
window.print();
window.close();
};
</script>');

Different Approach to Hiding image in Javascript

I'm responsible for developing an approach/algorithm to hide image on the trigger. But hiding should be in such a way that it would be hard for developers to do "inspect code" and change certain javascript variables or setting some condition true. So visibility:hidden is a no for sure because it's easy to get rid of it through "inspect code".
Only viable option I can think of is injecting image code () through JQuery which would make it quite work for someone to trigger it manually (I believe). But not sure if it's good enough.
What kind of an approach I can implement? Every opinion counts. Thank you.
To clarify: there are 2 images. each button hover will trigger visibility of one of the images. And the goal is to forbid the user from viewing both of them simultaneously. And they may avoid this by changing script conditions and variables. How to prevent that happening?
You could use something like the below to detect when someone uses inspect element to completely hide the content they're trying to change.
var currentHtmlContent;
var element = new Image();
var elementWithHiddenContent = document.querySelector("#element-to-hide");
var innerHtml = elementWithHiddenContent.innerHTML;
element.__defineGetter__("id", function() {
currentHtmlContent= "";
});
setInterval(function() {
currentHtmlContent= innerHtml;
console.log(element);
console.clear();
elementWithHiddenContent.innerHTML = currentHtmlContent;
}, 1000);
It will then show the content when they stop inspecting.

Ad Blocker detection AKA Adblock Plus

After searching Google and Stackoverflow for a few hours I could not find a solution.
What I'm trying to do is detect Adblock plus and display a simple message for now.
What I want to do is detect Adblock plus without using a JavaScript file or jQuery.
Most of the adblock plus detect scripts they use a file, example "show_ads.js" that is hosted on there own domain with a line it in to set it "adblock = false;"
The problem with using a JavaScript file, users can white list that JavaScript file and it will no longer detect it. What I'm looking for is a JavaScript that loads directly into the HTML that would detect if someone is using ad blocker without the use of a file.
Example Below:
<script type="text/javascript">
// line of code that detects if using ad blocker
if so display message
</script>
The reason behind doing it this way no ad blocker can white list the JavaScript file on your server. Yes I know there are other methods of getting around this with NoScript addons but I already have a solution for that. I have a great idea that has never been tried and ad blockers cannot block this once I get done with it.
Any suggestions and Examples will be greatly appreciated.
You don't need to have a plugin to detect adblock, simply use this:
<script type="text/javascript">
var adblock = true;
</script>
<script type="text/javascript" src="adframe.js"></script>
<script type="text/javascript">
if(adblock) {
//adblock is installed and enabled on this site :-D
}
</script>
Content of adframe.js:
adblock = false;
Update:
Adblock Plus blocks certain requests or hides certain elements based on patterns it already has. One of those patterns is this (in patterns.ini):
[Filter]
text=/adframe.
hitCount=843
lastHit=1456391595626
which blocks any URL that has /adframe. in it.
Update 25th august 2018
Adblock plus has changed the way it finds the list and blocks the ads. It has bunch of lists called subscriptions which are used for blocking. For example this one which is the default one:
https://easylist-downloads.adblockplus.org/easylist.txt
You can use the rules on this file to find a file name to use. For example you can use seo-ads.js
P.S for developers: For some reason I couldn't get ABP to block these files on local environment.
P.S: ABP is my favorite ad blocker :-D
Use my plugin "FuckAdBlock", it can very easily detect AdBlock:
https://github.com/sitexw/FuckAdBlock
Example :
fuckAdBlock.on(true, function() {
alert('AdBlock detected !');
}).on(false, function() {
alert('AdBlock is not detected =)');
});
Example online: http://fuckadblock.sitexw.fr/
What I've seen in the field is using a background image behind the ad. If adblock isn't active, the ad will be displayed over the background-image (which makes the background-image not viewable). If adblock is active, the ad is blocked, and the user will instead see the background-image.
<div id="ad-container">
<img src="../ad/ad.png" id="ad">
</div>
With CSS:
#ad-container {
background-image: url( http://domain.com/pleasedonotuseadblocker.png );
height: 200px;
width: 200px;
}
#ad {
height: 200px;
width: 200px;
}
If you want to ads to be showing, even when AdBlock is active, you'll have to understand what AdBlock is capable to do.
AdBlock can block resources from loading
AdBlock can hide specific elements in the DOM.
Although it is said that AdBlock can also modify CSS, I can't find any documentation on that other than hiding and collapsing elements.
So what exactly could you do to be 'smarter' than AdBlock?
You could disguise your request in a way that it will never be 'matchable' (e.g. http://domain.com/ae9a70e0a.png, where the image name will be random every time and without a common prefix). As far as I am aware, a rule in AdBlock cannot contain a regex. A rule would either match no ads, or too many resources. It would be possible to rewrite such an url on the server to point to your ad.
However, while AdBlock might not be able to block your ad from loading, it might still be able to hide it. There is no real way of going around this. There will always be a smart CSS selector that will -just- select your element. You could however add a background-image with content. This is not useful for an ad (not clickable), but might help you display an other message. Downside is that if someone decides to block that annoying background image, it will hide your content too.
As far as a script goes, you might be able to load the ad with an ajax request. I suppose (but cannot test) that it will give an error if the resource could not be loaded (because it was blocked). ($.ajax( request ).error( function() { ... } ); in jQuery or some equivalent in regular javascript). You could use that to do something else. You could include that in the document itself, instead of an external resource, to ensure it will always run (if javascript is enabled). Even then, you cannot be sure that 'whatever else you do' will ever be visibly displayed. As last resort you can make a window.alert( ... ). Assume that within 3 pages, your visitors will never come back if you use that.
An other way I can think of, is making a websocket to the server (afaik this cannot be blocked by AdBlock). On the server side you'll need to examine if the ad pages are not loaded when a certain page is loaded. This information can be sent through the socket, which can be used in your script to do 'something'. This, however, sounds crazy complicated and is a significant overhead for 'just' a script that detects AdBlock.
A simple Ajax call does the job:
var xmlhttp = new XMLHttpRequest()
xmlhttp.onreadystatechange = function() {
if( xmlhttp.readyState == XMLHttpRequest.DONE ){
if( xmlhttp.status !== 404 ){
console.log("Blocking ads")
}else{
console.log("Not blocking ads")
}
}
}
xmlhttp.open("GET", "/498100ffe815d700cd838d1/ads/showad.js", true)
xmlhttp.send()
Or even better, without the HTTP overhead:
var adBlockTester = document.createElement('div');
adBlockTester.innerHTML = ' ';
adBlockTester.className = 'adsbox';
document.body.appendChild(adBlockTester);
window.setTimeout(function() {
if( adBlockTester.offsetHeight === 0 ){
console.log("Blocking ads")
}else{
console.log("Not blocking ads")
}
document.body.removeChild(adBlockTester);
}, 60);
The following snippet will pretty much detect all ad blockers. Requires jQuery.
(function(){
var bait = 'http://googleads.g.doubleclick.net/pagead/gen_204?id=wfocus&gqid=advertisment&advert=ads';
$.ajax({ url: bait, dataType: "script"})
.fail(function () { alert('ad blocked'); })
.abort(function () { alert('ad blocked'); });
})();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
It's wrapped in a self-executing anonymous function so it doesn't interfere with other vars or code on the site.
The bait uses the most popular ad serving network (Google's double click) and includes a few other query params used by easylist and others.
The fail() and abort() methods are both required, but only one or the other will be invoked.
Don't put the code in adblocker.js or similar since those sort of filenames themselves get blocked from loading. Either inline it or include it in an random/arbitrary filename or combine it in your main site JS file.
Here is the code to detect adblock. You can learn how the code works here
function detect()
{
//create a iframe. Append the iframe to the body. And then after 100ms check if their offsetHeight, display or visibility is set such a way that user cannot see them.
//In the URL use the words specific to advertising so that Adblock can do string matching.
var iframe = document.createElement("iframe");
iframe.height = "1px";
iframe.width = "1px";
iframe.id = "ads-text-iframe";
iframe.src = "http://domain.com/ads.html";
document.body.appendChild(iframe);
setTimeout(function()
{
var iframe = document.getElementById("ads-text-iframe");
if(iframe.style.display == "none" || iframe.style.display == "hidden" || iframe.style.visibility == "hidden" || iframe.offsetHeight == 0)
{
alert("Adblock is blocking ads on this page");
iframe.remove();
}
else
{
alert("Adblock is not detecting ads on this page");
iframe.remove();
}
}, 100);
}
Simple javascript/jQuery detection that works nicely:
$('body').append('<div id="ad-container" style="position:absolute;"><img src="data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs=" id="ad"></div>');
var ad_container = $('body').children('#ad-container');
if(!ad_container.is(":visible")) {
// Add your warning and/or adblock detection logic here.
}
ad_container.remove();
The Smartest and easiest way I found is:
1) add this html code on somewhere in your markup probably on top.
<div id="bait" class="pub_300x250" style="color: #fff">.</div>
Usually ad blockers detect ad sizes of (pub_300x250) as mentioned in Easylist and blocked them, which is triggered by "bait".
2) then add this js code into your script file.
if (document.getElementById("bait").offsetHeight === 0) {
// function code or alert (whatever) here.
alert("Ad-Blocker DETECTED");
}
Our Script detects if that piece of markup is existed in present html by checking thorugh "bait" id.
This works for me with Adblock , AdBlock-Plus & uBlock Origin on every site on every browser.
For me none of the tricks worked, may something I was doing wrong. but this is a very specific way to implement for google ads.
window.onload = function() {
if (document.getElementsByClassName('google-auto-placed').length == 0){
// Adblock Detected
}
}
If you have other ad system like amazon, look for their generic class name / ids by inspecting page.
If you are planing to put this code in seperate .js file make sure file name does not have "Ad" word in it. just name it magic.js
If Google ever decides to change div name, this method would fail. but that seems unlikely.
In my case ADB was hiding the content even that there were no ads.. ( just because the ad word was present in many urls, because it was the post type slug.. )
But I noticed that they don't remove the content, just applying display: none to the body
So as an extra solution,
I just noticed that applying display: block !important; to de body, prevents hiding the content by Adblock plus
<body style="display: block !important;">
<img src="url-containg-ad-ads-word.jpg" alt="you should see this anyway" >
</body>
It's an arms race, for sure, and I support anyone's right to block ads, but I also support websites that depend on ad revenue trying to convince users otherwise, or perhaps persuade them to subscribe or make a donation to make up for lost ad revenue. I don't approve of sites trying to force users to see ads, but a polite message is fine.
Anyway, right now it's worth noting that there are many adblocking extensions/plugins, and they can all have different ways of doing it, and it sometimes is different between OSes and browsers too. I've found that for my purposes right now, this jQuery selector is enough to at least see whether AdBlock or AdBlockplus is being used, cross-platform, across at least Chrome and Firefox:
if($("div[id^=google_ads_iframe_] iframe:visible").length == 0) {
// pop up a message or whatever
}
Here is a simplest way to deal with it (no iframe, no jquery):
var elem = document.createElement('div');
elem.className = 'adclass';
document.body.appendChild(elem);
window.setTimeout(function () {
var isAdblockEnabled = !(elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length);
if (isAdblockEnabled) {
// Adblock is enabled
}
}, 0);
I know this is kinda old, but here's IMHO a better way to do it:
Add this to your <head> section:
<script type="text/javascript">
window.onload = function() {
var iframe = document.createElement('iframe'),
randomDomain = Math.floor(Math.random() * (10000 - 100 + 1)) + 100,
iframeLoaded = true;
iframe.src = "http://"+ randomDomain +".com/ads.html";
iframe.height = ".1px";
iframe.width = ".1px";
iframe.id = 'some-ad';
iframe.onload = function() {iframeLoaded = false;};
document.body.appendChild(iframe);
setTimeout(function() {
var someAd = document.getElementById('some-ad');
if(!iframeLoaded ||
someAd == null ||
someAd.style.display == "none" ||
someAd.style.display == "hidden" ||
someAd.style.visibility == "hidden" ||
someAd.offsetHeight == 0)
document.getElementById('ab-message').style.display = 'block';
someAd.remove();
}, 500);
};
</script>`<br>
Now you can use the ab-message id wherever you want to display a message to AdBlock users:
<div id="ab-message" style="display: none">Your message here!</div>
Note the inline style added to hide it originally (Of course, you can also do this from your own CSS file).
Also note that it takes 500ms, that's because it has to wait for the adblocker to do its thing or it won't work.
A little explanation of how this script works
First, it appends an iframe with a source of a randomly generated link. (It is randomly generated because some adblocks are smart, at some point, they realize a link is fake).
Then it runs multiple checks on that iframe (if it was loaded successfully or if its style was modified). If one of these tests is true, it then displays the ab-message element to adblock users.
This script works for most (if not all) ad blockers.
EXTRA
No point, really, could have just created a gist, but instead I created a Github project, but still, check it out and star it if it helped you.abDetector: Simple vanilla JavaScript AdBlock Detector.
Enjoy.
I have found one of the best scripts if you use third party ads.
antiblock.org Disclaimer I'm not affiliated with this site in anyway.
It will work for most sites and if they want to bypass it they will have to add their own filters (complicated for normal users) or contact adblock filters and have one added but they quit doing that cause the list is getting over loaded and slowing down ad block users.

Checking Third-Party iFrame Content [duplicate]

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.

Frame Buster Buster ... buster code needed

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.

Categories