My goal is to have watermarked images and protected originals for a node image field in D7.

How to add a watermark to images has already been explained: add watermark to all images uploaded in the site

What I'm missing is how to protect the original images! These are still available via direct url.

Someone solved the problem for D5: http://drupal.org/node/424068 but the mentioned rights are not present in D7 anymore.

An other approach is presented in the comments of this page: http://drupal.org/documentation/modules/file

  • Create a private filesystem
  • Change the field's filesystem to the private one
  • Use the content access module to protect the node (a), or
  • create a custom module and use the file_download() hook to prevent access (b).

Possibility (a) doesn't work for me as I don't want to protect the access to nodes, but only to the plain original image files. Possibility (b) hides the imagecached images as well.

6 Answers 6


You can try using an .htaccess to protect the directory containing the original images as mentioned at http://drupal.org/node/424068#comment-3149994

  • Thanks but this solution has some problems: first if you create a private filesystem like explained in the link above it WILL protect the files via .htaccess. In fact I cannot access the files via sites/all/files/private/filename.jpg. The problem is that drupal then makes them available programmatically via system/ the other possibility could be to protect the files folder directly, which is in my opinion not fine-grained enough: I want to protect only a very specific type of images, namely the ones posted to an image field of a node of a specific content type. Sep 1, 2011 at 9:12
  • was not fast enough to add the full path: it's system/files/filename.jpg Sep 1, 2011 at 9:20
  • I ended up discarding the private file system and using your solution, plus an "original" image style which doesn't alter the image for the image fields which I don't want to watermark. Sep 1, 2011 at 9:50
  • 1
    Wait, actually this doesn't work, because the styled images are located in a subfolder of 'files': blocking all pictures with .htaccess blocks also the styled images... Sep 6, 2011 at 13:48
  • This doesn't interfere with Drupal's ability to access the originals and generate cached images. Apr 26, 2013 at 4:48

You can write an API that retrieves images, via the Services module, and then in the "src" attribute of your image tags, as well as the URL for images in your CSS, you use an image retrieving API call. If you use the REST Server, then your image API calls look pretty much like any other url, just lacking an extension.

In your image API routine written in the Services framework, you capture all image requests and are able to get images from outside your web root. Just set your open_basedir so your php can reach outside of the web root, and the images are totally protected. Only your API call can retrieve them.

An interesting benefit of this is that you can optionally require image requests to include authentication. When a user is logged into a Drupal site, any API references in their page markup automatically carries their authenticated status, and your API routine will serve the images to the page being viewed by that user. However, if someone were to copy an image link and post that somewhere, the image won't load because that web page over there does not carry authenticated status for your site, and your API routine does not even get called because it failed authentication. Nifty. :)

(Also, to make it harder for people to even link to your images, embed them as a background image to a div in your CSS. That way, the user has to 'view source' and hunt down your image API call, because a context-menu click will not "show image".)

I use this API for images technique on a few sites, and it works quite well. In my image API, the REST API call looks like:


Which gives me contol to have different API versions for testing, different image containers for different user roles, and finally any image cache preset already defined.


This is an issue that you no doubt have spent a lot of time on and we have looked into it also. Its a very difficult issue. The problem is that you are serving a web page, and cannot avoid the fact that the images and content on the page are downloaded into a visitor's /temp folder when they visit your web page. Using firebug to inspect the DOM of your site can be a good way to understand the challenge of the exercise, when you see the way in which the component parts of a web page are downloadable.

You say you will have watermarked images, which is what you want, but will this present the right impression to visitors. For our designs, we felt it wouldn't.

Also anyone can simply press the 'print-screen' button and they have a copy of your image.

We've looked at this issue also and have sought the advice of others, many of whom said its impossible to prevent people copying your images, however you can make it difficult for them. There is some Javascript that prevents users right clicking on images then choosing 'download', but the general consensus is that this is very irritating for the visitor. And a determined person will just use something like Firebug/Inspector to get past this.

When we create image nodes that are used elsewhere, say in a view, we redirect the URL of the image node to the page with the view, in any event the image node is not normally used as a page. We also make sure that any thumbnails do not link through to the full image node, thereby avoiding a redirect loop. In this way you prevent the full image node from being accessed using URL Redirects.


  • 1
    Yes, that's the problem. And I understand that chosing not to use watermarks makes it impossible to really protect the images. Anyway watermarks are not so unusual, but how drupal handles the originals renders this solution useless. Some people might even wrongly believe they secured the images - it's a security issue. Sep 1, 2011 at 9:32

This is an answer attempt and doesn't work. I just put it here as a reference.

The cached image styles of private images are saved in the private filesystem as well in a "style" subfolder. Therefore in the file_download one must check if an original image is requested or an image style. The fast way (could be made more elegantly by adding some permission checks as in http://drupal.org/documentation/modules/file#comment-4104464):

function modulename_file_download($uri) {
    if (substr($uri, 0, 17) ==  'private://styles/') {
        return 1;
    } else {
        return -1;

The problem with this solution is that drupal first checks whether the original can be downloaded (which is not the case) and if not it directly forbids access to the cached styled image as well, without using this function. Somehow drupal doesn't want you to make only styled images accessible to the public :s


I just ran into this on Pantheon and am not sure if it is the same for all setups (they use Nginx) but what is working for me is is to set the imagefield path to private but set the download method to public. This way it actually puts the image file in the private protected directory but Drupal does not try to intercept the path request when the original image is requested. This means the protected directory permissions will work as they should. This is a fragile approach but it works and still lets imagestyles (imagecache) do it's work.

If you do this you can never link to the original image in "manage display" which is what you want of course but just so you don't think something is broken, remember to set an image style.

  1. Use subfolder in path for images you want to protect (configurable per-field in image field settings) eg "protected" so your uploaded images will land in "sites/[default]/files/protected" directory.

  2. Put regular Drupal's private path .htaccess within that directory:

    # Deny all requests from Apache 2.4+.
    <IfModule mod_authz_core.c>
      Require all denied
    # Deny all requests from Apache 2.0-2.2.
    <IfModule !mod_authz_core.c>
      Deny from all
    # Turn off all options we don't need.
    Options None
    Options +FollowSymLinks
    # Set the catch-all handler to prevent scripts from being executed.
    SetHandler Drupal_Security_Do_Not_Remove_See_SA_2006_006
    <Files *>
      # Override the handler again if we're run later in the evaluation list.
      SetHandler Drupal_Security_Do_Not_Remove_See_SA_2013_003
    # If we know how to do it safely, disable the PHP engine entirely.
    <IfModule mod_php5.c>
      php_flag engine off
  3. Users are still able to access images through styled directory eg. "sites/default/styles/protected/1.jpg" but won't be able to access original files.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.