Is the only solution to use Private - files transferred by Drupal in File System Settings ?

If I do use Private instead of Public, do I need to move my files to a directory unaccessible through the web. And what does that mean ?

I read this on the forum :

First of all: it's not requiered to move protected files out of document root - I think they may be placed in folder protected with .htaccess

What to you put in the .htaccess file in the folder to protect it ?

For example, if I am using the "files" folder and setting my Download Method to "private - files are transferred by Drupal", here is what I experience :

- putting http://www.myWebSite.com/files/ in the address bar redirects me to index.php. That's fine.

- HOWEVER, hotlinking to a file in /files is still possible : when I put the path to the file in /files I am able to access it, should it be .jpeg, .pdf wor whatever.

What am I doing wrong ?

How do people who sell downloadable goods or have premium content with attachments deal with these issues ?

Comments

ChrisKennedy’s picture

Private file downloads is the functionality you're seeking within Drupal.

There are also ways to use your .htaccess to restrict file downloads when the referrer doesn't originate from your site - try google to find em. Of course, the browser could always forge the referrer to get around this, if they're sneaky enough.

Chill35’s picture

Hi Chris!

I tried "Private" and it is still possible to "hot link" to the files in my /files directory by entering the full address in the address bar of the browser. And when I hover over the attachment, the full path to the file is shown in the status bar.

Is there something I need to do to my .htaccess file ?

Caroline

vm’s picture

Using the .htaccess method of anti-leech control is Pretty Wortthless and can often cause many problems for your website.

You may see htaccess code such as this claiming to provide anti-leech control for, in this case, gif jpg and png files. What this code does is stop any request that was not referred from the yoursite.com domain name.

RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_URI} !error.gif$
RewriteCond %{HTTP_REFERER} !yourdomain.com
RewriteRule \.(gif|jpg|png)$ /error.gif [L]

The problem is this anti-leech method relies on the http-referer code. The referrer is sent by the client (browser). That is the problem. Referrer is blocked by many firewalls and is not sent by many configurations. So you may think you have stopped leeching problems, when what you have really done is block many people from seeing your website.

You can kid yourself into thinking it works, and run a test that shows it does. But it only blocks people who are sending you an invalid referrer code. Maybe better than nothing, but not much better. All those people who get blockled will just go somewhere else assuming your website has too many errors since your images will not show.

To solve this problem, you see many examples like this:

RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_URI} !error.gif$
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !yourdomain.com
RewriteRule \.(gif|jpg|png)$ /error.gif [L]

The above example adds a line to let through any request which does not have a referrer code. Yes, this does allow all those configurations which block referrer code to see your images. However, if you open the door to allow anyone in with no referrer then you are watering down the protection to near worthless.

Then, to make matters worse, the referrer code can be easily faked anyway.

The htaccess anti-leech method is just plain Pretty Worthless. Do not use it.

If you want to protect your images, consider using a watermark and denying access to the original unwatermarked copy.

Chill35’s picture

What would we do without you Misunderstood ?

If you want to protect your images, consider using a watermark and denying access to the original unwatermarked copy.

How do I deny access to the original unwatermarked copy ?

I guess that if I cannot use some "rules" in the .htaccess file for my files folder, I have to move that files folder to the same level as the folder containing my Drupal site... ?

I wanted to avoid moving this folder outside the web root.

By the way, VM, thank you for all the help that you generously provide on the forums.

vm’s picture

denying access to original . meaning don't upload it. upload a watermarked copy only or.... use the watermark module to do this automatically.

Then even if your image gets hotlinked , at least you are getting advertising for the bandwidth. That is if you watermark it with yoursite.com.

Ideally if you have something you don't want people to have access to put it in a password protected directory using .htaccess. While you could store the files above the public root doc This would provide more overhead then if someone were linked to your images. (unless you are getting hammered). make a note check your server logs now and again and if a specific site is becoming a bandwidth hog without sending any traffic back to you from this linked image, block that specific domain from your site.

Chill35’s picture

I don't understand the advantages of going "Private" then. The word private is very misleading.

Let's put images aside. What I want to do is deliver PDF files.

Now I want only registered users to be able to access these files. I want only registered users to be able to access posts that contain these files as attachments. That part is easy. It's done.

Where do I put these PDF files ? In what folder ?

I want to prevent this :

Someone who is registered will download the file, i.e. will know where it is, then he/she will provide the link to the file to his friends or worst link directly to the file from a web site.

I must be very tired and feel very stupid.

Caroline

cog.rusty’s picture

Yes, the second HTTP_REFERER method will always let a user see your files directly. It is not access control. It will just make it hard for a systematic link thief to post direct links to your files, wasting your bandwidth.

Chill35’s picture

The only difference with "Private" that I am aware of is :

- addition of system in the path... to the file.

The file that is in http://www.mySite.com/files/documentation.pdf

is shown to be in http://www.mySite.com/system/files/documentation.pdf

Toggling between Public and Private adds and removes that "system" which is a folder that does not exist.

I really don't understand...

When I am logged off I am still able to download any file (by hotlinking) that is in my files folder, using Private!

Chill35’s picture

"Private download" is done using PHP.
"Private download" is done by Drupal.

If Private download is done through Drupal, there must be a way from Drupal to restrict download to users who are logged in and have a certain role.

No ?

ufku’s picture

private downloads has meaning when you use a file system directory outside your web root. Then the files cant be accessed from web however php has still access to them and can serve them to users.

--
Geneticists from METU

Chill35’s picture

private downloads has meaning when you use a file system directory outside your web root. Then the files cant be accessed from web however php has still access to them and can serve them to users.

I will try that one as well.

THANKS!!! That makes sense to me.

cog.rusty’s picture

Good question. I had to go through it and try a few things. This is how it works (I think).

In general, access control for private files is up the module through which the file is accessed. In particular, the (core) upload.module does support this.

All you have to do is disable the "view uploaded files" permission for "anonymous user" for upload module in admin/access.

For more advanced control, you can enable "view uploaded files" for everyone and then use an access control module such as taxonomy_access for more fine grained access per user role: Any user roles you have specified won't be able to view a private file if they are not allowed to view the node where it was uploaded (the 'system/files/filename' link will give them a "page not found").

Chill35’s picture

All you have to do is disable the "view uploaded files" permission for "anonymous user" for upload module in admin/access.

Unfortunately I want users who are not logged in to be able to download certain files, and not others.
Maybe I will have to change that.

By the way I am using the premium module to block access to content with restricted file attachments.

I guess it's an all or nothing for users who are not logged in.

I will try it though.

Chill35’s picture

If I am using "Private download"...

And my file is inside the root of my Drupal website, and I am logged out and Anonymous users cannot view or download files, then :

Accessing directly http://www.website.com/system/files/doc.pdf will generate an "Access Denied" message BUT accessing the file directly for viewing and download will be possible for anyone who is able to guess where it actually is : http://www.website.com/files/doc.pdf (easy to guess for people who know Drupal doh).

Is that a bug ?

On the other hand, if my file is on the same level as the root of my Drupal website, and I am logged out and Anonymous users cannot view or download files, then :

Accessing directly http://www.website.com/system/files/doc.pdf will generate an "Access Denied" AND
this is the only way to access the file.

My setup is like that :

+
   + Drupal folder containing index.php
   + DrupalPrivateArea folder

My File system path is set to :

../DrupalPrivateArea instead of

files

QUESTION :

I guess I can "put" the images I am not uploading in my files directory and link to that directory...?
Say : in a post I use an image, I use "files/myImage.png" as href attribute ?

Chill35’s picture

Whether I use as File system path ../DrupalPrivateArea or .../DrupalPrivateArea the files are succesfully uploaded to DrupalPrivateArea.

Why ?

cog.rusty’s picture

It is not all or nothing. With something like the taxonomy access module you can tag nodes with categories which anonymous users can view and with categories which they can't. Probably there are also access control modules which let you set up anonymous access for individual nodes.

What is important is that the file link does not work for a user who does not have access to the node where the file was uploaded.

I have not tried the premium module, so I don't know what it can do.

Chill35’s picture

Whether users can see nodes or not is not an issue when it comes to downloading files through hotlinking.

If the Taxonomy module is able to restrict "viewing downloads" (not nodes) to a certain type of anonymous users, than that would be great. Do you think the module can do that ?

It's ok if you're not sure. I will try it anyway.

Now I have just run into a major road block. I think I will have to just give up on Drupal, because in the HTML of any content, we cannot put relative links to images in the src attribute if we want to use clean urls. We can only put the "relative" path to the root of the server... when moving an installation from one server to another, all content in the database that has links to stuff in the files folder, will have broken links in it. That is a show-stopper.

cog.rusty’s picture

About taxonomy access control, I did do some testing before my first post here. With private downloads, the direct link to 'system/files/filename' stopped working the moment a user did not have access to the node where the file was uploaded.

Of course if the real path of the file is web-accessible it is beyond Drupal to control it. It is between you and Apache. Well... maybe if the real 'files' path name is absurd enough a user won't guess it...

About the src path with clean url's, I couldn't understand what the problem with moving is. Paths relative to Drupal's installation directory seem to work for me.

As for trying other CMSs, I did it a couple of times. Some CMSs do have more sensible default settings but I always missed the flexibility. With some luck you may stumble on one which fits closely to your needs.

Chill35’s picture

Please take a look at this node : http://drupal.org/node/102667

When clean URL is enabled, Drupal writes absolute paths for everything that is linked to on the web page (stylesheets, pictures...). It uses /path/To/My/Drupal/Installation/DrupalIinstallationFolder/path/to/file...
Do a View Source in the browser.

Trouble with content (stories, pages) is that it falls flat on the page unaltered.

The browser really thinks that the web page url is http://www.mysite.com/node/15... for example. So it tries to find an inline image on the page with relative path "files/image.jpg" in that "directory", i.e. the browser tries to open the file http://www.mysite.com/node/15/files/image.jpg. Of course there's no such file, so the link is broken.

About the src path with clean url's, I couldn't understand what the problem with moving is. Paths relative to Drupal's installation directory seem to work for me.

cog.rusty’s picture

Oh, I remember now. This is often discussed in theming.

The standard advice is either adding a front slash and Drupal's base directory, which does make the link unmovable, or prefix with <?php print base_path() ?>, which is unsuitable for the end user (only for theming).

Once I did ask a couple of questions myself but I got blank stares and I had to get over it and started offering the same advice, plus the advice to use a text editor on the database backup to change the base directory in the links. Not as neat as it could be but it works.

Maybe this can be revisited when Drupel 6 development opens for business. But people will ask for code submissions.

Chill35’s picture

Yes exactly...

so to print inline images, which I will always put in /files ...

<img src="<?php print base_path() ?>files/picture.jpg" alt="some picture" />

I tested it and it works... :)

However some other guy may have a solution, using :

I set $base_url in my settings.php file. Probably should of done that first thing. That seems to have worked. Thought I'd post it in case someone else comes across the problem in the future.

http://drupal.org/comment/reply/101852

Maybe I can use src="/files/...." all the time BUT tell Apache what is the root... in my setting.php

Do you know how this works, do you think it can solve the problem ?

I have learnt much today!

cog.rusty’s picture

The $base_url is required when you have Drupal in a subdirectory and access it as a subdirectory (not as a subdomain). That guy's problem was with something which did use the $base_url. I don't think it is used in image links.

Chill35’s picture

I tried about 20 combinations and I can see that the $base_url has to be commented out or written in full
(http://localhost/DrupalFolder) otherwise it breaks everything, and it does not resolve the image url problem.

It's kind of strange that there aren't many complaints about that. Maybe most people use img_assist and stuff like that. img_assist adds much overhead (macros to HTML content) and ONLY works with tinyMCE which is quite buggy and ugly. It's like using a hammer to do kill an ant.

cog.rusty’s picture

A new module called IMCE is becoming popular lately for uploading and placing images.

But I don't suppose any module can create portable links if they can't be created even manually. At best, a module will insert the right base URL for the current site. At worst, it will insert a full URL.

Anyway, using subdomains instead of subdirectories, a front slash is always enough.

Chill35’s picture

Yes. A front slash as in <img src="/files/picture.jpg" alt="Some picture" />

But to test it on my machine (localhost) do I really need to move everything down to htdocs ?

I need to test other sites on my machine. Including Drupal 5 beta 2. That's why I use subdirectories.

I think that the solution for now is a rewrite rule in the .htaccess file. But I can't figure out how to write it yet.

In a rule you can keep a substring that matches a pattern and change the url so that this string and everything that follows becomes the new url that is used by Drupal. Just one line.

Hence it does not matter if you make a call to Drupal with
http://www.mySite.com/node/4/files/picture.jpg

What it will get, after rewriting it, will be
http://www.mySite.com/files/picture.jpg

I am sure that IMCE does not hard-code the path. It is probably calling the Drupal function base_url, using the upload module to get images in the Drupal directory, and using a global variable to know the path to this folder, etc. I will check it out. I am relying on Douglass's book and what he recommends in that book are old modules, including Flexinode.

cog.rusty’s picture

You don't need to move everything down to htdocs. You can have them in subdirectories but access them as subdomains by defining different vhosts in your apache httpd.conf, like this:

<VirtualHost dru47.localhost>
ServerName dru47.localhost
DocumentRoot "C:/blablabla/htdocs/drupal-4.7"
</VirtualHost>

<VirtualHost dru5.localhost>
ServerName dru5.localhost
DocumentRoot "C:/blablabla/htdocs/drupal-5"
</VirtualHost>

(The server names could be just dru47 and dru5.)
Then, also update your Windows' hosts file for these names.

This way, everything will be at the document root of a different vhost and moving to a real site will be more straightforward.

See:
http://drupal.org/node/32715
http://gleez.com/drupal/multisite
http://httpd.apache.org/docs/2.0/vhosts/examples.html

I saw your .htaccess rewrite question but there was something too hackish about that solution...

Chill35’s picture

About taxonomy access control, I did do some testing before my first post here. With private downloads, the direct link to 'system/files/filename' stopped working the moment a user did not have access to the node where the file was uploaded.

Yes that's true with or without Taxonomy control. For example, if you choose that id-0 users cannot view downloads then they won't be able to open the file with the "system" in the path.

Of course if the real path of the file is web-accessible it is beyond Drupal to control it. It is between you and Apache. Well... maybe if the real 'files' path name is absurd enough a user won't guess it...

YES absolutely. So it should not be in files LOL...

As for trying other CMSs, I did it a couple of times. Some CMSs do have more sensible default settings but I always missed the flexibility. With some luck you may stumble on one which fits closely to your needs.

At that point it's like talking about me changing boyfriends. I'd rather go celibate. Cannot imagine CMS without Drupal, so... I'll change career path I guess LOL... become a nurse.

No, but seriously, there's always a solution. I know there's one. I hope it does not involve using a whole bunch of modules like image, img_assist, tinyMCE, etc... just to put a darn inline image in a post.

I could use php to create content. What is the php function that gives me the path to the file ? The function arg(). Then using php I could build the proper path for the image from there, going : for each arg(i) call that returns something valid, I'd put a ../ then add files/ the the file name and extension... and voilà. That solution does not involve a whole bunch of scripts to run and database accesses...

Chill35’s picture

With something like the taxonomy access module you can tag nodes with categories which anonymous users can view and with categories which they can't.

The premium module works that way :

- you can decide on a node-basis (not content type, not category) what is premium content and what isn't : "Am I hiding this particular article/story/blog node from Anonymous Users ?" If I want to, then I check the "premium content" box in the Publishing options of the post. (And in Access Control, Anonymous users are "set" to be strangers to premium content).

Chill35’s picture

I guess it's an all or nothing for users who are not logged in.

I stand corrected. Taxonomy access or Premium don't make it an all or nothing deal.

ufku’s picture

using this function, you dont need to worry about base_url or private/public download methods. ex: <img src="<?php print file_create_url('images/foo.gif') ?>" />
as in the example you just specify a path relative to your file system path. the foo.gif, in this case is in "your_filepath/images/foo.gif"

--
Geneticists from METU

cog.rusty’s picture

True, but there is still the question, when:

- Drupal is installed in a subdirectory
- Clean URLs are enabled

How can a user manually enter an image in a node without php input format enabled, using a path which does not depend on the name of the subdirectory where Drupal is installed, and does not break when Drupal is moved?

ufku’s picture

you should forget about no breaking when Drupal is moved, if you use inline images or files in nodes. that's only possible with php or a special input format providing tokens like %filepath, %baseurl etc.

if you want your users insert paths outside of drupal directory, you should be using private downloads with a private file path. your private file path will be symbolized with system/files/ in URLs. Therefore, a subdirectory installation wont matter. Inline images/files will still cause problems when moving drupal because urls will be like "/subdir/system/files/...".

To conclude, what you are asking for is nearly impossible especially when the site depends on user input.

--
Geneticists from METU

cog.rusty’s picture

That's what I thought... So, the way Drupal currently works, the only fail-safe way for end users to enter path-independent links is to use special image tags processed by an input filter, rather than html tags.

Lowell’s picture

Similar to most of the above posts, I have moved my files folders out of the www accessible tree.

Drupal file system is set to private and points to the new files folders.

Access control for uploaded files is not checked for anonymous users.
Am also using nodeaccess with grant tab, and anonymous users are not checked there either

When I log out and use the Drupal path to the files, I have access to them, for example

example.com/system/files/image.jpg

My understanding is that Drupal is supposed to block access to this folder.

Maybe some code in the right place would solve my problem?
for example:

if user is not logged in, grant no access to the system/files folders

or even more specific, only if user is logged in and has grant access to a particular node/id then can view only associated system/files/image.jpg's

thanks in advance

Anonymous’s picture

I do experience the same behaviour.
I cleared the cache, cleared private date and sessions and I am still able to access the files through:
http:///system/files/images/test.gif

The actual location of the files is outside the document root, so direct access is normally not possible. Thanks to private files they are directly accessible!

Having said that and considering the disadvantages, why on earth would I need to use private files in the first place?

I issued a bug report for this because in my opinion this is a very serious issue:
http://drupal.org/node/141109

EDITED:
SORRY:
It does work for file attachments. However it does not work for image content types!
I will post an issue for the image project

Joep

-----------------------------------------
CompuBase, websites and webdesign