views:

383

answers:

6

The job at hand:

I want to make sure that my website's users view a page before they start a download. If they have not looked at the page but try to hotlink to the files directly they should go to the webpage before the download is allowed.

Any suggestions that are better than my idea to send out a cookie and - before the download starts - check if the cookie exists (via .htaccess)?

The webpage and the download files will be located on different servers.

Environment:

  • Apache 2 on all machines
  • PHP 5 on all machines
  • MySQL 5 available on the "webpage" server (no access from the download servers)

Nathan asked what the problem is that I try to solve, and in fact it is that I want to prevent hotlinks from - for example - forums. If people download from our server, using our bandwidth, I want to show them an page with an ad before the download starts. It doesn't need to be totally secure, but we need to make some money to finance the servers, right? :)

+1  A: 

You could use distributed server side sessions instead of cookies, but that is probably more trouble than it's worth.

You could also forbid access to requests without a referrer or with a wrong referrer. But that's even more fakable than a cookie.

It'd depend on how much you care.

Vinko Vrsalovic
Servers will be spread out over the internet, so the session solution is not what I want... The forbidden access is also one solution that I had in mind and I might go with it, because cookies will probably cause too much trouble.
BlaM
+5  A: 

Instead of allowing hotlinking to the files, store them outside of a web accessible route. Instead make download requests go to a php script that initiates the download. You can put checks in place to ensure that the requesting page was the one you wanted read.

Brian Warshaw
Going through a PHP file is not really what I want. Thought about that, but I prefer to let apache handle the transfers. What I might do is set up "temporary symlinks" to the downloads through a php file if everything is okay (website was viewed).
BlaM
Fair enough. Sorry I couldn't be a better help.
Brian Warshaw
Any input welcome - doesn't matter if I pick it or not ;)(The main problem with your solution is that I have to deal with downloads with hundreds of MBs. It would be a pain in the a** to implement "resumeable downloads" - not even talking about the memory usage for such huge files).
BlaM
The memory usage wouldn't be a problem -- you just send small chunks. But the resumable part would be a pain.
scotts
+2  A: 

An Apache mod_rewrite RewriteRule can do this.

RewriteEngine on
RewriteCond %{HTTP_REFERER} !^http://www.example.com/page.html$
RewriteRule file.exe http://www.example.com/page.html [R=301,L]

Basically, if a request for file.exe didn't come with page.html as the referrer, it'll 301 redirect the user to page.html.

ceejayoz
The problem with referrer checking is, that there are many "referrer blockers", so you have to allow requests with an empty referrer. Also: The referrer will not always be the same, but that's just a matter of "regexp".
BlaM
I tend to doubt referrer blockers are common outside a very, very small techie demographic. Depending on the type of files you're providing, it may be a demographic you can afford to ignore. Varying referrers is easy, as you say - a quickie regular expression and you're all set.
ceejayoz
They're common enough that the solution wouldn't work for everyone, and becoming more popular all the time.
scotts
A: 

I was about to suggest the .htaccess referral trick, but it isn't a very secure method. It's easy to make a PHP script, with a custom http-referral added. If you enter the download page there, it will think you come from that page.

Is this a relevant problem? Can you tell something about the context of your download page?

Gerrit
+1  A: 

The solution here depends on the problem you are trying to solve. If you are just trying make sure a direct link doesn't get posted in forums and whatnot, then just checking the referrer with .htaccess should be enough. Of course the referrer can be faked easy enough, so if the risk of someone doing that is a problem, then you'll need to do something else.

A cookie should do the trick if you need something a little more secure. We cannot just use php sessions because the file server and the webserver are on different boxes. But we could create a cookie based on a hash of the time, and some secret value.

cookievalue = sha1('secretvalue'.date('z-H'));

When the user requests the actual file, the fileserver generates this cookie again and makes sure it matches the users. This means, even if the user forges the cookie, it will be invalid after an hour, so who cares, and they can't generate their own new one, because they do not know the secret value.

Nathan Reed
A: 

I'm going to use mod_auth_token to make sure that the user has a "recent link".

With mod_auth_token you can create expiring links, i.e. if someone decides to take an existing link and post it on another website, this link will expire after a specified time. That will result in a 403 FORBIDDEN which I can catch and redirect the user to the HTML page I want him on.

BlaM