Forum Moderators: open

Message Too Old, No Replies

State of the Art Frame Buster / Proxy Buster

         

incrediBILL

6:25 pm on Mar 3, 2011 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



I noticed some framing sites are also now becoming proxy sites and serving up your website code via the proxy to filter out your frame busting scripts. Some of them allow your javascript to run but filter out things like "top.location.href =" to thwart your frame buster.

I also ran into the worse case scenario, the proxy didn't even use a frame, they simply injected their proxy stuff into your HTML so it easily defeated things like "if ( top!=self )" because the location was always top and self without frames!

Here's my quick and dirty solution that could be made a little more elegant but literally appears to bust any proxy or framing site I've thrown at it so far, assuming they don't filter out your javascript altogether.

mypath="http://www.example.com/somepage.html";
if ( top.location.href.substr(0,mypath.length) != mypath ) eval( "top." + "location." + "href" + "= '" + mypath + "';" );


The trick that seems to confuse their proxy filters at the moment is the eval() statements stop the filters from seeing a raw "top.location.href" and further obfuscation would make it even more difficult to stop with simple filters.

Since many people are now using canonical tags in the header you could probably make this more elegant by actually reading mypath from the canonical tag.

caribguy

7:33 pm on Mar 3, 2011 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Thanks incrediBill!

Back when I ran sites that were likely to get framed, I also used to pass the offending URL to the busting script. Makes it easier to find out who is abusing your content....

incrediBILL

10:02 pm on Mar 3, 2011 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



That's a good point.

I think I'll add the current top.location.href as a URL parm when I execute the redirect so it'll get logged.

Fotiman

10:27 pm on Mar 3, 2011 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



In the case of a proxy where they're doing a man-in-the-middle attack, the top.location.href check won't detect that case (because the location IS your site... just with some extra code stuffed into it).

As for frame busting, yes, using eval is one way. Another way is to assign each object in the path to top.location to a variable.

Here's one way you could do it:


/**
* @param u {Object} The configuration object which consists of valid hostnames
* as "keys" and the url to redirect to when a bad site is found.
*/
(function (u) {
var w = this, // the window object
t = w.top, // the top property of the window object
l = t.location; // the location property of the top window
if (!u.hosts[l.hostname]) { // Check to see if this host is in the hosts list
// If not, replace (not redirect) to the default location for this page
// and include the bad site where it might be logged for tracking purposes
l.replace(u.default + "?badsite=" + encodeURIComponent(l.href));
}
})({
hosts: {
"www.example.com": 1,
"www.example.net": 1
},
default: "http://www.example.net/mypage.htm"
});


Note, I deliberately made this code lengthy to better explain what it is doing. it could be minified down to something like this:

(function(u){var w=this,t=w.top,l=t.location;if(!u.hosts[l.hostname]){l.replace(u.default+"?badsite="+encodeURIComponent(l.href));}})(
{hosts:{"www.example.com":1,"www.example.net":1},default:"http://www.example.net/mypage.htm"});


That example allows you to specify multiple valid hosts. For example, if you ever wanted to allow 1 or more specific sites to put your code in a frame, you could simply add the hosts to the list of hosts. Note, in this example I've given each host a value of 1. It doesn't matter what the value is as long as it is a not a falsy value. I could have used true instead of 1, but 1 is the most compact. Likewise, I could block certain specific sites by giving them a falsy value (like 0).

Next, I map this (which is the window object in this context) to variable w, window.top to the t variable, and window.top.location to the l variable.

Next I do a lookup to see if the current location.hostname (not href), matches one in the list. Since in most cases you only care whether it's hosted on your server, this is really all that's needed to check (and prevents having to add http AND https variants, or any other possible multiple path variants, or keep editing the list if you move the file to a different location on your own host). If the current host doesn't match one in the list, replace the location to the "default" url that was passed in the configuration, and (as caribguy suggested), pass along the URL in case you want to track who is trying to put your site in a frame.

It's fairly simple yet extensible, doesn't rely on eval, and should provide the same level of protection as the eval approach.

incrediBILL

10:47 pm on Mar 3, 2011 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



See, that's an elegant solution, very nice!

Except you still didn't pull the default out of rel canonical for true elegance. :)

Fotiman

2:17 am on Mar 4, 2011 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



Ok, here's an example that attempts to fetch the default canonical tag, but also takes a default fall back value (for example, in case a proxy is stripping off the canonical tag).


<!DOCTYPE html>
<html>
<head>
<link rel="canonical" href="http://www.example.com/mypage.htm" >
<title>My Page</title>
</head>
<body>
<h1>My Page</h1>
<script>
function getCanonical() {
var i,
lnks = document.getElementsByTagName('link');
for (i = 0; i < lnks.length; i++) {
if (lnks[i].rel && lnks[i].rel.toLowerCase() == 'canonical') {
return lnks[i].href;
break;
}
}
return null;
}
/**
* @param u {Object} The configuration object which consists of valid hostnames
* as "keys" and the url to redirect to when a bad site is found.
*/
(function (u) {
var w = this, // the window object
t = w.top, // the top property of the window object
l = t.location; // the location property of the top window
if (!u.hosts[l.hostname]) { // Check to see if this host is in the hosts list
// If not, replace (not redirect) to the default location for this page
// and include the bad site where it might be logged for tracking purposes
l.replace(u.default + "?badsite=" + encodeURIComponent(l.href));
}
})({
hosts: {
"www.example.com": 1,
"www.example.net": 1
},
default: getCanonical() || "http://www.example.com/mypage.htm"
});
</script>
</body>
</html>