Hot Linking, Secure Token, Allow Domains, General Security

Here is a complete Wowza Module to deny hotlinking server-side. Compile this in the Wowza IDE:

package com.lakesidetechnical.security;
import com.wowza.wms.amf.*;
import com.wowza.wms.client.*;
import com.wowza.wms.module.*;
import com.wowza.wms.request.*;
public class HotlinkDenial extends ModuleBase {
	public void onConnect(IClient client, RequestFunction function,
			AMFDataList params) {
		getLogger().info("onConnect: " + client.getClientId());
		String pageUrl = client.getProperties().getPropertyStr("connectpageUrl").toLowerCase();
		String domainLock = client.getAppInstance().getProperties().getPropertyStr("domainLock").toLowerCase();
		
		boolean reject = !pageUrl.startsWith(domainLock);
		
		if (reject)
			client.rejectConnection();
	}
}

Then add this Module last in the Modules section of your Application.xml

Hotlink Denial

Hotlink Denial Module

com.lakesidetechnical.security.HotlinkDenial

(note that I cannot get rid of the space between the “a” and “l” in HotlinkDenial above, be sure to edit that out)

And this Property section to the Properties section below the Modules in the Application.xml:

domainLock

http://localhost

This zip file includes a compiled jar file:

http://wms.lakesidetechnical.com/hotlinkdenial.zip

Richard

Ok…not that there was any doubt but I placed a link to my swf on a different domain on a different server and low and behold, I was able to play my member videos with no problem.

I’ve now added the following to my htaccess to prevent hot linking. It did prevent my test page from working but I don’t know if it’s a good idea or not.

RewriteEngine on

RewriteCond %{HTTP_REFERER} !^$

RewriteCond %{HTTP_REFERER} !^http://([-a-z0-9]+.)?mydomain.com [NC]

RewriteRule .(jpg|jpeg|png|gif|swf)$ - [NC,F]

I looked up some obfuscator programs and one (http://www.kindisoft.com) looked promising as it has ‘Encrypted Domain Lock.’ Of course it’s the professional version and costs $400.

I need to eventually allow other domains to access my free material. My plan (which I already started) was to create a new app with its own secure token and hand out the swf with the matching secure token. I originally thought this would be enough for security. Obviously I need more. I guess using the obfuscator program I could make a custom swf for each new domain but that would be a lot of extra work.

Tying the .swf file to the html page also sounds like a lot of work. I have many unique pages each with their own unique video (times 2 when you add in the member section) and it’s constantly growing.

Just sharing and thinking out loud.

Regards,

Jake

You could just link them to your domain. In onConnect handler do something like this:

String pageUrl = client.getProperties().getPropertyStr("connectpageUrl");
boolean reject = !pageUrl.startsWith("http://my.domain.com");

Then accept/reject the connection based on this info. That way only the domain part needs to match.

Charlie

Thanks for your suggestion Charlie.

I know it’s not your job to act as programming instructor/advisor but not only do I not know how to implement what you suggested, I don’t even know what part of my posting your suggestion is referring to.

I think I’m coming to the realization I’m in over my head :eek:

Can you comment on the htaccess hot link protection?

Best Regards,

Jake

Put it in com.jeroenwijering.models.RTMPModel.as in the load() function.

Add import to the top:

import flash.external.ExternalInterface;

And modify load() function:

/** Load content. **/
override public function load(itm:Object):void {
// Add from here:
var href:String = "";
if (ExternalInterface.available)
{
href = ExternalInterface.call("function(){return window.location.href;}");
}
if (href != "YourWebsite.com")
{
// handle bad domain.
return; // just refuse to load RTMPModel and your done. You don't owe anyone an explanation.
}
// end Add
	item = itm;
	position = 0;
	model.mediaHandler(video);
	connection.connect(item['streamer']);
	model.sendEvent(ModelEvent.BUFFER,{percentage:0});
	model.sendEvent(ModelEvent.STATE,{newstate:ModelStates.BUFFERING});
};

Richad

Thanks Richard! This looks like something even I can try. Just to clairify however, all I need to change is;

if (href != “YourWebsite.com”)

I’m away from the office at the moment but will post my (successful) results later.

Best Regards,

Jake

Yes, but trace it out and see exactly what it is and don’t forget about localhost. This is what I get from what I am working on now:

href=

Richard

well…no luck so far. the preview image appears but nothing happens when I click on it.

I’m using JW Player 4.4.198

I’ve tried MyDomain.com, www.MyDomain.com and http://www.MyDomain.com but none of them worked.

I’ve tried moving the ‘import flash.external.ExternalInterface;’ line around in the top of the file with no luck.

I don’t know how to trace it out. I Googled trace as3 and there were a lot of suggestions but I don’t understand them.

I checked the logs and nothing is showing up there.

Help:confused:

@Rikison, I haven’t tried your method yet. Does it require the actual html page or just the domain?

@Richard, Okay…after days of trying to understand the trace(); thing and how to perform it I almost gave up. I finally came across a plugin for FF that displays all trace requests/functions/what ever it’s called. That’s when I realized it was looking for a specific html page and not just the domain. Once I added my html test page address to the AS I was able to get it to work.

Can you confirm that this is indeed correct (the entire address…http://www.mydomain.com/somefolder/wowzatest.html is needed)?

If this is the case, please forgive me for stating the obvious, does that mean I need a different swf player for every video that’s on a different html page? As of right now, I have 24 different videos on 24 different pages and that number is growing weekly.

Also, if I don’t encrypt the swf, couldn’t someone decompile it and remove the request. Again, if that’s the case, why bother with this and not go right for the obfuscater.

@Charlie, any development the module front?

Thanks!

I have not had a chance to test but I wanted to say thanks to everyone!

Wow, this post seems very similar to the one I posted the other day. However you seem to have gotten a much better response. :slight_smile:

Since a few days has passed since my post I spent a good 2 days trying to figure something out. Im also the man with every hat for my business and feel very similar to you.

I dont mind sharing what took me an insane amount of hours and a huge headache. I scoured the web and tried every as3 actionscript I could find. I finally ended up with this:

/*
fast&dirty domain lock in as3
by dx0ne http://dx0ne.laislacorporation.com
based on http://www.flashrights.com/domaincontrol.htm
*/
gotoAndStop(1);
import flash.events.*;
import flash.display.LoaderInfo;
function enterFrameHandler(event:Event):void {
	var url:String=stage.loaderInfo.url; //this is the magic _url successor
	var urlStart:Number = url.indexOf("://")+3;
	var urlEnd:Number = url.indexOf("/", urlStart);
	var domain:String = url.substring(urlStart, urlEnd);
	var LastDot:Number = domain.lastIndexOf(".")-1;
	var domEnd:Number = domain.lastIndexOf(".", LastDot)+1;
	domain = domain.substring(domEnd, domain.length);
	
	if (domain != "nothing" && domain != "domain1.com" && domain != "domain2.com") {
		gotoAndStop(34);
	}
}
addEventListener(Event.ENTER_FRAME, enterFrameHandler);

Change the domain1.com and so on to your domain, and add as many domains as you want.

Now I will explain how I got it to work with the JW player. Basically download the .fla source code from the JW Player 4.4 HERE.

Open the FLA and make a new layer and paste the above code on frame one. Make another layer and put a keyframe on frame 34 and put whatever you want there, a link to your site maybe or a bad message.

I also added this to my .htaccess which is a little different than yours, Im not sure which is better.

RewriteEngine on
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http://domain1.com/.*$ [NC]
RewriteCond %{HTTP_REFERER} !^http://domain2.com/.*$ [NC]
RewriteRule [^hotlinked].(swf)$ http://domain1.com/flashfile.swf [R,NC]

Same goes with the flash code, I saw someone else pasted some code but Im not sure which is better.

The question I have is, can I improve on anything to help this problem? Is the other flash code better? Having something supported by wowza would be the best option, please help us out Charlie!

OK, I tried the other flash script posted before mine and it looks like its as2 and not as3. the new jw player is as3 only from what I can tell. Is that correct?

Im trying that code in Flash CS4 and Im getting a compiler error.

1013: The private attribute may be used only on class property definitions.

Source: private var href:String = "";

Any ideas how to fix it?

Also, does this prevent against people simply putting the embed into a folder that is named what your website is? So for example:

www.otherdomain.com/files/yourdomain.com/embedpage.html

And even worse than that is does this help again dns masking where I here they can set up a dns zone or something to be called your domain.

Please forgive me.

Im trying to get this working simply with the JW player and im sure many people would like to know how to get this working on a very basic level. I myself dont know actionscript at all.

I have he latest jw player (4.4) and I made a new layer and put this on frame 1 (of course I did change the domain name, but it errors either way)

var href:String = "";

if (ExternalInterface.available)
{
href = ExternalInterface.call("function(){return window.location.href;}");
}
if (href != "YourWebsite.com")
{
// handle bad domain.
}

This is the compiler error I get now that I removed the word private

1120: Access of undefined property ExternalInterface.
Source: if (ExternalInterface.available)

and

1120: Access of undefined property ExternalInterface.
Source: href = ExternalInterface.call("function(){return window.location.href;}");

Im not doing anything else, just trying to keep things as basic as possible. Thanks for your help!

@ Richard

Thanks for that, what version of the JW Player are you using? It seems to be a bit different in 4.4. I dont even see a load function, this is the only place in the file that talks about loading something.

    /** Load content. **/
    override public function load(itm:Object):void {
        item = itm;
        position = 0;
        model.mediaHandler(video);
        connection.connect(item['streamer']);
        model.sendEvent(ModelEvent.BUFFER,{percentage:0});
        model.sendEvent(ModelEvent.STATE,{newstate:ModelStates.BUFFERING});
    };

@ Charlie

Thanks! Ill have to try this out too. However Ive been told that .htaccess rules can by bypassed with browsers that dont offer a referrer or something along those lines. Though it should work for most situations from what I understand. Perhaps this tutorial is beyond the basic .htaccess I posted earlier. Ill post my results.

I did a quick test and it wasnt working right but I need to try it a couple more times to make sure its not something else. I kinda ran out of time for now but will try again and post the results. If anyone else has any luck please let us know!

I still havent got around to this but dont forget I did post a working solution and how to do it in a previous post. Id like to get a consensus on what is best.

@Jake It requires just the domain, and from what I can tell it works great. Id love other people to try and let me know.

Ive been thinking about this and there are a couple of things that I think would greatly improve the security and not only that but give much more control for us when streaming videos to customers.

The first thing Id like to mention is new to this thread but it would be great to be able to restrict the person who views the file to a specific IP or IP Range. So wowza would need to get the IP information from the person trying to watch the video and allow or deny it based off a rule that checks a range. I dont know if this is even possible but it would be nice. Is this possible with IDE?

The second thing of course is being able to restrict the media from being played on an IP or Domain. So in this case wowza would check the IP or domain where the player itself lives and allow or deny based off this rule. I know Charlie said this is possible and even easy to do with IDE, but could we get a working example so I could test it out?

THanks, I sent the email and will try this and report my results.

Awesome, I cant wait to test this.

I assume we can just add multiple domains by a comma and space?