We run an online service (aka a script) and we have discovered a few websites over the past few weeks putting our script on their site via iframe.
What precautions can we take to stop other people putting our site into theirs via iframe?
Thank you.
A more global solution would be something like this:
<script type="text/javascript">
if (top.location != location) {
top.location.href = document.location.href ;
}
</script>
Place it on the top of your page (inside the "head" tag).
On modern browsers, send the header X-Frame-Options with the value DENY. If it's a recent enough browser, it'll obey the header and tell the iframe to pack sand.
Related
I'm using the following code to use as a form of nulling referring script and it works perfectly but it just redirects them straight to the target URL.
How would I go about creating a 5 second delay so I can display some adverts for 5 seconds before redirecting them?
You can send php header with timeout refresh. http://php.net/manual/en/function.header.php
<?php
header( "refresh:5; url=wherever.php" );
?>
What about using sleep()?
function method1(...) {
sleep(5);
... rest of the code
Note however that it is more recommended to use Vahe Shadunts's answer, which uses header() instead.
The refresh header does the job but I'd like to highlight some potential issues:
It is not specified in the HTTP standard. Wikipedia says:
Proprietary and non-standard: a header extension introduced by Netscape and supported by most web browsers.
But it has been around for almost 20 years now and I don't know of any browser that does not support it (could not find a reference though)
Some browsers do not use the cache on a page redirected with refresh. It has been demonstrated for Internet Explorer here: http://blogs.msdn.com/b/ieinternals/archive/2010/05/13/meta-refresh-causes-additional-http-requests.aspx and I coud reproduce it on Firefox. Chrome does not have this issue.
Alternative: JavaScript
You can add a JavaScript on the intermediate page, that opens a new page after X seconds. Add this at the bottom of the page to redirect to http://www.example.com/target after 5 seconds:
<script type="text/javascript">
window.setTimeout(function() {
window.location.href='http://www.example.com/target';
}, 5000);
</script>
Combination
As a bonus, you can fall back to the refresh header if JS is disabled, using the meta directive http-equiv that tells the browser to act as if a certain HTTP header has been sent. Because it is part of the HTML source, you can wrap it in a <noscript> element. Add this to your <head> additionally to the JavaScript above:
<noscript>
<meta http-equiv="refresh" content="5;url=http://www.example.com/target" />
</noscript>
Now, the page redirects with JavaScript if available for the best performance, and uses refresh otherwise.
My CMS links to other sites for convenience and I'd like to hide the referer so that other sites don't see the directory and the query string of my CMS. I now have the CMS linking to a PHP file elswhere on my server which in turn redirects to the link via header() but the referer is still from my CMS, not from the linking PHP. Furthermore...
header("Referer: nowhere");
header("Location: $_REQUEST[urltolinkto]");
... doesn't appear to change anything. No matter what I put as referer, it's always the one from my CMS where the user actually clicked on the link.
Can the referer be changed (to the linking PHP), or do I have to use javascript or meta refresh?
The Referer header is something the browser sends to the Server. You are changing the respose from the server to the browser, so that will not work this way (unlike the Cookie header). As far as I know you have no server-side control of the browser's behavior on sending the Referer.
The browser does get to choose what referrer to send, but there are ways around it.
HTML5 added meta referrer, most modern browsers will respect it. Just add
<meta name="referrer" content="no-referrer">
to your site's head.
There's also redirection services and other hacks to hide the ref (https redirects, iframe tricks and others).
A good solution is to simply use the classic <META HTTP-EQUIV="REFRESH" CONTENT="0; URL=http://www.example.com/">.
In fact, Google Analytics has a help page specifically for this question with users who ask about web-tracking not working on redirects, here: Support.Google.com -> Redirects: Place the tag on redirecting pages. They explain the problem quite well:
If your site uses redirects, the redirecting page becomes the landing page's referrer. For example, if you've changed your site so that index.html now redirects to home.html, then index.html becomes the referrer for home.html....
For this reason, you should place the Analytics tag on the redirecting page as well as on the landing page. This way, the redirecting page will capture the actual referrer information for your reports.
So, just swap out header("Location...") with a massive series of print statements. This feels so inelegant. But it works.
Note: I'm also throwing in a canonical attribute so browsers understand the point of the redirect more clearly.
<?php
$redirect_url = 'https://www.example.com';
$google_analytics_configgtag = '12345, this is your api key';
print('<!DOCTYPE HTML><HTML><HEAD>');
print('<META HTTP-EQUIV="REFRESH" CONTENT="0; URL=' . $redirect_url . '"/>');
print('<LINK REL="CANONICAL" HREF="' . $redirect_url . '"/>');
if($google_analytics_configgtag) {
?>
<!-- Global Site Tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=<?php print($google_analytics->configgtag); ?>"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments)};
gtag('js', new Date());
gtag('config', '<?php print($google_analytics_configgtag); ?>');
</script>
<?php
}
print('</HEAD>');
print('<BODY></BODY></HTML>');
?>
You cannot set Referer header manually but you can use location.href to set the referer header to the link used in href but it will cause reloading of the page.
You cannot really change the referer from server-side as it is provided by the browser to the server.
But you can use a service like href.li, just use
https://href.li/?http://<your-url>
Note: http:// after ? is important or it will not redirect.
I have an iFrame that does some background processing. When this processing is complete I would like to re-direct the user to another page, but the header change code is only affecting the embedded iFrame. Is there a way to target the main window?
I have seen the deprecated Meta redirect have a target attribute, but I don't know how widely it is supported.
In Javascript:
top.location.href = "resultpage.htm";
Works only if the top frame is on the same domain as the emitting page.
For a solution that works across domains and without Javascript, the following would work:
Continue
Use JavaScript to track content of frame, if content change, redirect browser :)
We can use javascript like this:
target.window.location='locationpage.php';
parent.window.location='index.php';
For me this always works without fail, have tried many of the others but there always seems to be some sort of issue....and it does not matter if headers have been sent etc.....
<?php
echo "<script>window.location = 'http://www.google.com'</script>";
?>
Remember this goes at the very bottom
How can I find out that my page is embedded as a frame to other site during page loading? I guess referrer request header can't help me here? Thanks.
You cannot check it from the server's side, but you can use javascript to detect it after the page has loaded. Compare top and self, if they're not identical, you are in a frame.
Additionally, some modern browsers respect the X-FRAME-OPTIONS header, that can have two values:
DENY – prevents the page from being rendered if it is contained in a frame
SAMEORIGIN – same as above, unless the page belongs to the same domain as the top-level frameset holder.
Users include Google's Picasa, that cannot be embedded in a frame.
Browsers that support the header, with the minimum version:
IE8 and IE9
Opera 10.50
Safari 4
Chrome 4.1.249.1042
Firefox 3.6.9 (older versions with NoScript)
Stackoverflow includes some JS to test it (master.js). This is the relevant part of it:
if(top!=self){
top.location.replace(document.location);
alert("For security reasons, framing is not allowed; click OK to remove the frames.")
}
But keep in mind that JS can be disabled.
For modern browsers, you can use CSP (Content Security Policy), which is a standard. The following header will prevent the document from loading in a frame anywhere:
Content-Security-Policy: frame-ancestors 'none'
(IE 11 needs the X- prefix, though). You can also change 'none' to the origin on which framing is allowed, such as your own site.
To cover the older browsers, this is best used together with #Maerlyn's answer.
you can prevent loading you page in an iframe with javascript
<script type="text/javascript">
if ( window.self !== window.top ) {
window.top.location.href=window.location.href;
}
</script>
this code change address of container of your page's iframe to your page address and force container to show your page.
Or you can block a specific domain if you don't mind your content in some locations but don't want it on a certain site. For example, if offendingdomain.com was embedding your content, you could do this:
<script type="text/javascript">
if(document.referrer.indexOf("offendingdomain.com") != -1) {
window.location = "http://www.youtube.com/watch_popup?v=oHg5SJYRHA0";
}
</script>
This would check the parent document's location and see if it's the offendingdomain.com that is embedding your content. This script will then send that iframe to a certain famous youtube video as punishment. In effect they just Rick-Rolled themselves.
Use javascript to check if it was loaded on iframe by placing the following script at the end of your php file and redirect to a page that displays warning or notice that your page should not be loaded using iframe.
<script type="text/javascript">
if(top.location != window.location) {
window.location = '/error_iframe.php';
}
</script>
<?php
header("Content-Security-Policy: frame-ancestors 'none'");
?>
Replace hosname to domain name
if (window.top.location.host != "hostname") {
document.body.innerHTML = "Access Denied";
}
I using this PHP code on top of the header
if($_SERVER['SERVER_NAME'] != 'yourwebsite.com'){
header('location: yourwebsite.com');
}
if someone did iframe your site it will redirect to your website
I have a page that does the following:
The browser loads a very simple page with a valid head and body, with only a script/noscript pair as content.
In the body, it has a script (script a) that runs a function onLoad. This function dynamically includes a second script (script b), and runs a function in it when it becomes available.
The second script is a .js file that does various work.
Both scripts are parsed by PHP and use the application/x-javascript content type.
Now, I have this all working just fine, except a couple of JS hiccups. JavaScript isn't one of my strong languages, so I'm hoping these are simple issues and somebody can point me in the right direction.
Problem 1: If I do a simple alert('you are in script b'); in the second script, it works as expected. However, if I do anything else, it works fine, and then the browser keeps indicating that it is loading forever. This is the color tween in firefox, or the spinning thing in IE.
I've tried ending the script in different ways, and nothing seems to help. Any idea how to indicate to the browser that the script is all the way loaded? It's a .js file that is forced to parse through PHP.
Problem 2: The second script doesn't seem to be included at all in either Opera or Google Chrome. Works fine in FF/IE, other than the loading issue. Can anyone see if Im using something that isn't compatible in the loading of the second script?
Thanks!
Update:
Thanks for the answers. I actually have firebug, which is why I know everything is working properly (in FF, at least). I don't actually know that the script isn't working in Opera/Chrome, but nothing happens.
It is quite a bit of code =o) I will copy the actual responses out of firebug and post those, so you can see exactly what the code is. As far as the webserver closing the connection, I was thinking that too, but it seems odd that if I make script b into alert('whatever'); it will alert and then stop loading, but it I do everything exactly identical, but make the script document.write('whatever); it will load forever.
Here are the scripts, updated, copied directly from the net tab of firebug:
Note that discoverfire.net is an internal domain, so you won't be able to load anything from there...
Initial HTML page:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>Welcome!</title>
<style>body { font-family:arial; }</style>
<script language="JavaScript" type="text/javascript" src="http://www.discoverfire.net/analytics/l/a.js">
</script>
<script language="JavaScript" type="text/javascript">
document.onload = Start();
function Start(){
TAFKing_version = '1.0';
TAFKing_lkey = '19-8O-KKA8HV';
TAFKing_Lander();
}
</script>
</head>
<body>
<noscript>
Oops! We can't forward you properly because your JavaScript is turned off.<br /><br />
<a href='http://www.discoverfire.net/analytics/l/noscript/19-8O-KKA8HV.html'>Please click here to continue.</a>
<img src='http://www.discoverfire.net/analytics/l/imp/19-8O-KKA8HV.png' border='0' alt='tell a friend' />
</noscript>
</body>
</html>
** Script A (...a.js): http://www.discoverfire.net/analytics/l/a.js **
function TAFKing_Lander(){
version = TAFKing_version;
lkey = TAFKing_lkey;
var scrb = document.createElement('script');
scrb.type = 'text/javascript';
scrb.src = 'http://www.discoverfire.net/analytics/l/b.js?lkey='+lkey+'&version='+version+'&cb=4eohe8e65'
;
document.getElementsByTagName('head')[0].appendChild(scrb);
Interval = setInterval("Waiter()", 10);
return;
}
function Waiter(){
if(window.TAFKing_LanderB) {
clearInterval(Interval);
TAFKing_LanderB();
}
}
Script B (...b.js): http://www.discoverfire.net/analytics/l/b.js?lkey=19-8O-KKA8HV&version=1.0&cb=4eohe8e65
function TAFKing_LanderB(){
document.write("there are just a whole bunch of doc.writes here that build a simple table");
}
I bet it is nothing related with the scripts, but with the webserver. Your description, specially that it affects many browsers, and some of them don't even run the scripts, leads me to believe that the webserver is not closing the connection. Perhaps the webserver is not properly handling HTTP/1.1 Keep-alive requests.
Try using Firebug in Firefox. Install it, enable it for your page, reload the page and check the "Net" tab for what really is keeping the connection open.
This is a lot of code to go through. You should definitely get Firebug to help you diagnose it. The latest version will even show you when/if the onload events occur.
Firebug will also allow you to output message simply by writing console.log('somevar=',var); to test their values. You can even use the console to test value after the page has loaded since you're using the global name space.
Off the top of my head, I would make sure the connection properly closes in php. Also
document.onload = Start();
would assign the result of Start() to onload, not Start which is defined later.
Also window.onload is more compatible/standard.
You may want to save the output of your js files as outputphpA.js and outputphpB.js, directly source those and see if the loading behavior differs. That should help diagnose if it's a php issue.