Hot Link Prevention, embedded objects included

Short HOWTO:

Put contents of this zip file in the directory you want to be protected. Read the files and change what seems necessary. On your web pages, where you are going to have media content in, change the source path and add this in the head section:

   <script src="/path/to/hotlinkp.js" type='text/javascript'>
   </script>
 

Anywhere you want an embed object added, just add this:

   <script>
       make_link("458","Anathema: A Simple Mistake<BR>");
   </script>
 

It can be modified easily to do whatever you need. Leave me a comment if you need help on it.
NOTE: I intended to add more features, but didn’t find neither the time nor a reason to do so, and then release it. If someone needs something of it, I’ll be glad to add features.
To read the full step by step creation of these,

A friend of mine publishes different sorts of digital content on his website/weblog. His main intention is to have embedded audio files in his blog, just to make it easier for the viewer to listen them. His daily traffic has reached 4GB to 6GB per day. For instance on 01 August 2006, he had 3682 visits equal to 30239 hits consuming 6.38 GB of bandwidth. Detail of the accessed files?

  • 48.4 % Audio
  • 37.3 % Image
  • Third place is HTML or XML static page with 12.7 % share of the hits.

This amound of hits/visits generates a ~390GB monthly bandwidth usage which is way too close to his bandwidth limits.

A closer look at his log files showed most of the traffic originated from search engines, mp3/wma search engines and especially hot linking of other people. If you don’t know about hot linking here is a good intro on hit linking:

Hot linking is probable one of the most popular ways for users to steal bandwidth and copyrighted material from other webmasters. Basically anything that someone links to, that resides on another user’s web hosting account is considered hot linking. Users also call it Leeching. This can be anything from images to files.

We step by step compiled necessary scripts to block hot linkers and mp3/wma search engines or even google to access the copyrighted material. If you have the same problem, this might be usefull to you too. To use the same method, you must be running Apache web server with mod_rewrite enabled, able to run php scripts. If you do not have Apache, you can convert it to work for you. The concept is quiet the same.

After using this method, the traffic dropped from 383GB in July to 189GB in August. In September, traffic decreased to 139.84 GB. Daily average was 8.99 GB in July which is 4.85 GB in August,and 4.66 GB in September.

Step 1

Well, first of all we added a simple javascript function. It would generate the download links of audio files, mostly .WMA files, and also the embed html tags required. The concept was something like this:

   function make_link(name)
   {
   var server="www.mydoamin.com";		//change this
   var dir="/blog/songs/";			//change this
   var link="http://"+server+dir+name;
   var link+=".w"+"m"+"a";			//change this
   var embed="<br /><br /><embed pluginspage=http://www.microsoft.com/Windows/MediaPlayer/ src=\"";
   embed+=link;
   embed+="\" width=70 height=26 type=\"application/x-mplayer2\"";
   embed+=" ShowControls=\"1\" autostart=\"0\" loop=\"0\"><br />";
   document.write(embed);
   }

As a result, after a while search phrases like "Song XYZ filetype:wma" would no longer point to his site in search engines like Google.

Step 2

This time we had to remove the hot linkers of images. This can be done easily using cPanel’s integrated hot link protector. If not using cPanel, this .htacces would do good:

	RewriteEngine on
	RewriteCond %{HTTP_REFERER} !^http(s)?://(www\.)?yourdomain.com [NC]
	RewriteRule \.(jpg|jpeg|png|gif)$ - [NC,F,L]

You can generate a usefull .htaccess on this site. Just place the resulting .htaccess in the directory where your content is residing.

Step 3

NetShow Player (media player) counted for 50 % of the hits in (for instance) July 2006. This is equal to 140GB of the bandwidth! How much of this is our own visitors? Not much I guess. Most of it from people embedding audio files in their homepages.

Hot link protection of images may be simple, but what about embedded objects? NetShow player, Windows Media Player, Real Player and other similar ones usually do not send referrer data to the web server. Look at this line of access log on that server:

   85.182.xx.yyy - - [07/Aug/2006:02:51:23 -0600] "GET /blog/songs/243.wma HTTP/1.1" 200 30679 "-" "NSPlayer/10.0.0.3646"

This means that someone with IP address 85.182.xx.yyy has tried to "GET /blog/songs/243.wma". It has got a 200 status code, means it was OK for him to do so. 30679 bytes were transfered. No referrer data has been sent, the "-" after the indicates. The user agent, browser, has been NSPlayer which is NetShow Player. Since it has not sent a referrer the regular hot link protection based on referrer is useless. If we use that .htaccess trick here, even content on our own pages won’t work.

To stop others from putting our content on their pages using embed method, we did the following:

1-Added afunction called encrypt to our pages:

   function Encrypt(theText)
   {
		num_out = "";
		str_in = escape(theText);
		for(i = 0; i < str_in.length; i++)
		{
		   num_out += str_in.charCodeAt(i) - 23;
		}
		return num_out;
   }

2-Changed the make_link(name,desc) javascript function to something like this:

function make_link(fm,desc)
   {
		var d = new Date()
		var t= d.getFullYear()+"/"+(d.getMonth()+1)+"/"+d.getDate();
		t=encodeURI(Encrypt(t));
		var server="www.mydoamin.com";		//change this
		var dir="/blog/songs/";			//change this
		var link="http://"+server+dir+name;
		var link+=".w"+"m"+"a";			//change this
		var embed="<br /><br /><center>";
		embed+="<embed pluginspage=http://www.microsoft.com/Windows/MediaPlayer/ src=\"";
		embed+=link;
		embed+="\" width=70 height=26 type=\"application/x-mplayer2\"";
		embed+=" ShowControls=\"1\" autostart=\"0\" loop=\"0\"><br />";
		address="<a style=\"font-style: tahoma, arial; font-size:80%\" href=\"";
		address+=link;
		address+="/"+t+".wma"; 
		address+="\">";
		address+=desc;
		address+="</a></center>";
		document.write(link+address);
   }

3-In the .htaccess, I forbid direct access to the .wma filetypes. Only requests matching the pattern created by the javascript function were redirected to a PHP script:

		RewriteEngine on
		RewriteRule ^(.*)\.wma/([^\.wma]*)\.wma$  redirect.php?file=$1&t=$2 [nc]
		RewriteCond %{REQUEST_URI} ^(.*)/([0-9]{1,4})\.wma$
		RewriteRule ^(.*)$   - [f,nc]

This way, a link like http://www.mysite.com/blog/songs/1234.wma/12345678.wma would be translated to a request like http://www.mysite.com/blog/songs/redirect.php?file=1234&t=12345678
and the red.php is something like this:

 <?php
$myDoaminNames=array("mysite.com","mysite2.com");	//a list of different doamin names I have
$myExtension=".wma";								//extension of files: .wma/.mp3/.mpeg/...
$myTimeLimit=86400;									//the amount of time the code is valid in seconds

//this function unencrupts the digital code generated by the JS
   function unEncrypt($str)
   {
	   for($i = 0; $i < strlen($str); $i += 2)
	   {
		   $num_in = (int)(substr($str,$i,2)) + 23;
		   $str_out .=chr($num_in);
	   }
	   return $str_out;
   }
	$t=($_GET['t']);		//get the code
	$filename=$_GET['file'];	//get the filename desired
        $file=$filename.$myExtension;
	if (!is_file($file))		//catch non-existant file requests
	{
	   header("HTTP/1.0 404 Not Found");
	   die();
	}
	$t2=unEncrypt($t);		//Attention: TIME OF BROWSER'S CLOCK! 
							//user could be in Iran, server could be in USA
	$now = date("Y/m/d");	     	//Attention: LOCAL TIME of server
	$diff=strtotime($t2)-strtotime($now);
	//we give people one day chance to use the same download `code`
	if ($diff > 86400 or $diff < -86400)
		$expired=true;
	else
		$expired=false;
		
	//which browser is requesting? Firefox? IE? NSPlayer? RealPlayer?
	$browser=$_SERVER['HTTP_USER_AGENT'];		
	//what referrer data is sent to us?
	$referer=$_SERVER['HTTP_REFERER'];		

	if (stristr($browser,"NSPlayer") || stristr($browser,"Media") )
		$embed=true;
	else
		$embed=false;
	if (in_array($referer,$myDoaminNames))
		$ref=true;
	else
		$ref=false;
	//if referrer is set and is OK, or it is an embedded content AND the code is not expired
	if ($ref || ($embed && $expired==false) )
	{
		header('Content-disposition: attachment;   filename="'.$file.'"');
		header('Content-Type: audio/x-ms-wma;');
		header('Pragma: anytextexeptno-cache', true);
		header('Content-Transfer-Encoding: Binary');
		header('Content-length: '.filesize($file));
		readfile($file);
	}
	else
	{
	   /*
	   just to test, needs a writeable file called log in the same directiry to write logs into it
	   $fp=fopen("log",a);
	   fwrite($fp,print_r($_SERVER,1)."\n");
	   fwrite($fp,"embed=".$embed."\n t2=".$t2."\n && expired=$expired\n--\n");
	   fclose($fp);
	   */
	   echo ">h1<leeching not permitted>/h1<";
	}
?>

Alternative method

If all of your pages are written in PHP, or any other dynamic programming language, you register IP addresses of visitors and let them download only if their IP address appears in the recent visitor list. The idea is similar to session tracking, but this time no data is kept on user side.

Improvement

  • Make the random generator function a web service, and make it available only to your own web server.
  • Give each file type a code, and then while requesting swend this code too.
  • Double check the .htaccess rules. Some file names may not match the forbidding rule, hence people can access them.

Leave a Reply

Your email address will not be published. Required fields are marked *

Time limit is exhausted. Please reload the CAPTCHA.