Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

I am using WordPress multisite (3.3.1) and am trying to protect uploads from certain blogs from being hotlinked and directly accessed. This is loosely related to How to Protect Uploads, if User is not Logged In?, but I only want the uploads to be accessible through scripts running on the server (IE. the server alone can display/serve uploads), so the content can be protected by WordPress user-rights.

For example, I have a filed called 40c.jpg located at localhost/files/2011/07/40c.jpg; I want the file to show up only when called by HTML on the local domain (here: localhost). So not on any other site on the WordPress Network, any other domain or when accessed directly (IE. visiting localhost/files/2011/07/40c.jpg).

Preferably, this would be done by using WP_Rewrite within functions.php of the theme for this site; as that would easily limit the impact to just that site. But using the .htaccess in WordPress root also is a viable option, though I assume that would mean that the domain itself would have to be specified there (IE. localhost).

Any suggestions on how to accomplish this? I've had very little luck through searching StackExchange, WordPress.org and Google.

share|improve this question
    
Read on SO. This is off-topic. –  kaiser Apr 11 '12 at 14:04
    
I think he's talking more about how to stop the images from loading at all on certain sites of multisite based on user privileges; this isn't just about hotlinking, but about restricting media to even the subsite within a network. –  John P Bloch Apr 11 '12 at 14:11
    
@JohnPBlock is right, I am only trying to make the restriction work on certain blogs within the multisite; and after completely blocking public access make the uploads visible to specific users (based on privileges). This should be apparent from the first paragraph of my question. –  OleVik Apr 11 '12 at 14:50

2 Answers 2

You've got some issues in your underlying objective ...

For example, I have a filed called 40c.jpg located at localhost/files/2011/07/40c.jpg

OK, this makes sense and is where the image should be in the first place.

I want the file to show up only when called by HTML on the local domain (here: localhost). So not on any other site on the WordPress Network, any other domain or when accessed directly (IE. visiting localhost/files/2011/07/40c.jpg).

This is where you have a problem ...

When you reference an image in an HTML block, the HTML isn't calling/serving the image. Your server gives the HTML to the browser, the browser parses it and sees the image reference, then the browser goes back out and asks your server for the image.

For example, here's the actual network activity for images on my own site: Example Screenshot

For that big code image in the header, my server returns this markup:

<img width="600" height="300" src="http://mindsharestrategy.com/files/2010/12/code.png" class="attachment-Slideshow" alt="code" title="code">

My browser sees that, and makes a separate request for the image, downloads the image from the server, and renders it on the screen.

If I wanted to limit who can load this image, I would add on the server some code to intercept the request, check the value of the Referer header, and either return the content or not.

This handling is 100% outside of WordPress. No WP_Rewrite. No plugins. Nothing done with your theme. You might be able to get Apache to do this with a combination of changes to .htaccess and httpd.conf, but that's a sysadmin task beyond the scope of this site.

share|improve this answer
    
I see; this also explains why my solution does not work. Would it be possible to do some kind of check within ms-files.php to deny serving images to non-authorized users? –  OleVik Apr 12 '12 at 19:32
    
There is no way to hook in to ms-files.php before it begins returning content. –  EAMann Apr 12 '12 at 20:26

There are a few ways to effectively handle this, most of which requires the use of a plugin or plugin-like behavior (see Adding mod_rewrite rules to htaccess and WP_Rewrite in the Codex). The problem really lies in how WordPress handles uploads in a multisite environment, and how to apply a RewriteRule that only affects a specific site.

A helpful user at the WordPress.org forums suggested adding the following (just below "# uploaded files" in the .htaccess file in the root of WordPress):

RewriteCond %{HTTP_HOST} ^somedomain\.com
RewriteCond %{SCRIPT_FILENAME} ^([_0-9a-zA-Z-]+/)?files/(.+)
RewriteRule ^([_0-9a-zA-Z-]+/)?files/(.+) - [L]

Where somedomain would be the domain to disallow direct access to files to. Also, adding Options All -Indexes and this:

# ultimate hotlink protection
<IfModule mod_rewrite.c>
 RewriteEngine on
 RewriteCond %{HTTP_REFERER}     !^$
 RewriteCond %{REQUEST_FILENAME} -f
 RewriteCond %{REQUEST_FILENAME} \.(gif|jpe?g?|png)$           [NC]
 RewriteCond %{HTTP_REFERER}     !^https?://([^.]+\.)?domain\. [NC]
 RewriteRule \.(gif|jpe?g?|png)$                             - [F,NC,L]
</ifModule>

prevents directory listing and hotlinking (from Perishable Press), respectively.

Hopefully, this will be made easier to deal with in future versions of WordPress (see Ticket #19235: Turn ms-files.php off by default).

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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