Manual:Image authorization

This article is for system administrators who wish to restrict access to images and files based on user and/or user group permissions.

Uploaded files are generally served directly by the web server, not through mediawiki. While there is a minimal level of security through obscurity with path encryption (eg. /c/c4/...), the path can be calculated easily from the file name and does not provide true protection.

This is not a recommended configuration; MediaWiki is not designed to be a CMS, or to protect sensitive data. To the contrary, it was designed to be as open as possible. Thus it does not inherently support full featured, air-tight protection of private content. Any administrator wishing to use this functionality should carefully review Security issues with authorization extensions

Overview
By default, all uploaded images (and files) are accessible directly by the web server. If you wish to allow access only to authorized users within the MediaWiki framework, two conditions must be met:


 * 1) The actual directory must be protected from direct access and;
 * 2) MediaWiki Authorization must be invoked when an Image/File access occurs by executing a script when any url containing that directory is requested.

The fundamental implementation requires:


 * 1) The images directory ($wgUploadDirectory) should be moved outside the web root on the file system or otherwise protected
 * 2) The upload path ($wgUploadPath) should point to img_auth.php

The mechanisms for both are dependent on the web server platform. This article gives detailed instructions for two platforms:


 * 1) Apache (most versions)
 * 2) Microsoft Internet Information Server (IIS), version 6.0 and higher

For all instruction, assume that my MediaWiki is installed in "/path/to".

For example in:

http://wiki.yourwiki.org/MyWiki

"/path/to" is "/MyWiki"

Another Scenario, Security Motivated
Even if you don't want to restrict access to your images you might want to make use of the img_auth.php mechnism: to avoid publicly accessible directories, where the web server has write permissions. Though a web server writable directory is not insecure in itself, it is the first half of a successful attack to your web server. The second half then would be some exploitable (php) script, be it MW or, most likely, some other script. If the attacker can exploit the broken script to upload or generate another script intented to help him with further attacks/spamming etc, the attacker still needs a place to store that script in, writable by the web server ... and has it available and well known in the 'images' directory of MW standard installations.

A very first security measure against this will be to place a .htaccess file inside the 'images' directory with this content: php_admin_flag engine off And that .htaccess must not be writable by the web server! It is a pitty, that MW doesn't come with this by default (at least not in 1.6.10).
 * 1) No php execution in the upload area

But even better will be to also move the web server writable 'images' directory outside of the document root, renaming it to something unguessable (e.g. the MD5 hash of &lt;whatever&gt;) and streaming the images via 'img_auth.php', so that the real directory name never ever shows up.

To accomplish that follow these steps:

cd &lt;/absolute/path/to/your/doc_root&gt;/.. mkdir &lt;dir_name_unguessable&gt; chgrp &lt;your_web_server_group&gt; &lt;dir_name_unguessable&gt; chmod 770 &lt;dir_name_unguessable&gt; cd &lt;dir_name_unguessable&gt; echo 'php_admin_flag engine off' &gt; .htaccess chmod 444 .htaccess $wgUploadPath = "$wgScriptPath/img_auth.php"; $wgUploadDirectory = '&lt;/absolute/path/to/your/doc_root&gt;/../&lt;dir_name_unguessable&gt;'; $wgEnableUploads = true; $wgWhitelistRead = false; (actually this doesn't work properly.. you need to hack your img_auth.php  and remove the check for logged in users and if the image is in the whitelist.. comment these lines: if( !$wgUser->getId && ( !is_array( $wgWhitelistRead ) || !in_array( $title, $wgWhitelistRead ) ) ) {     wfDebugLog( 'img_auth', "Not logged in and `{$title}` not in whitelist." );    wfForbidden; } if anyone could make that a configuration option, it would be great!)
 * 1) login in to a shell of your web server (similar actions are often possible with your FTP client, if not, ask your provider to assist you)
 * 2) create the unguessable images/upload directory outside of (in parallel to) your document root (note the /.. at the end of the path):
 * 1) make it read/writeable for the web server:
 * 1) create the .htaccess file as noted above and make it readable only (this is paranoia, because the web server never looks here, only PHP not taking care of .ht* files normally, but just in case this directory ever will be made available to the web server directly) :
 * 1) change your LocalSettings.php config file:
 * 1) We don't wanna restrict access, just make our MW install more secure

That should do the job for web servers with PHP running as an Apache module. No further Apache config file changes are neccessary. You then will never see the path to your images, img_auth.php intercepts all read accesses. But all of your images are served, including thumbs.

If you use CGI or IIS your milage may vary.

How Does img_auth.php Work?
Image authorisation works by "intercepting" the URL and checking to see if the remainder (PATH_INFO) is in an area where the user has access based on the standard User ID and any Namespace, etc. protections you've assigned. When you've set up the upload path $wgUploadPath, to point to a directory that automatically redirects to include a script in the path, the script is executed and determines whether or not the file should be accessed.

What is really happening is this. If your pointer to the image/file is set up to http://wiki.yourwiki.org/MyWikiImg/01/01/Trash.txt, this is translated to http://wiki.yourwiki.org/MyWiki/img_auth.php/01/01/Trash.txt by MW and the server actually executes img_auth.php passing it "/01/01/Trash.txt" in the PATH_INFO server variable.

img_auth.php then checks to see if the user has access to that particular file and if so, streams it back. If not, it displays a standard 403 error.

Configuring File Uploads
Before attempting this configuration it is very important you understand Configuring file uploads. Please take a few moments to review and understand this article - it will save you a lot of time.

PHP PATH_INFO Support
This requires that your PHP setup support PATH_INFO (many CGI configurations do not) and you need to be in $wgWhitelistRead mode or else, there wouldn't be a point ... unless you just like a more secure MW install, see above.

Apache Instructions
Most administrators have found implementation in an Apache Environment straightforward and fairly simple.

Apache Step 1. Protect Images Directory from Internet Access
In your [/path/to]/images directory, create an .htaccess containing one line:

Deny from All

Note: If you have not moved your directory, you do not have to change $wgUploadDirectory

Apache Step 2.1. Change $wgUploadPath in LocalSettings.php
$wgUploadPath = "[/path/to]/img_auth.php";

Apache Step 2.2. Create aliases to execute img_auth.php
Edit the httpd.conf file and add the two following aliases:

Alias [/path/to]/images/ [/path/to]/img_auth.php Alias [/path/to]/images [/path/to]/img_auth.php

Apache Step 1. Download the cgi-supporting image authorization script
When PATH_INFO is not available download the CGI-supporting image authorization script. Save script under the name cgi_img_auth.php in your mediawiki directory.

Apache Step 2. Protect Images Directory from Internet Access
In your [/path/to]/images directory, create an .htaccess containing one line:

Deny from All

Note: If you have not moved your directory, you do not have to change $wgUploadDirectory

Apache Step 3.1. Change $wgUploadPath in LocalSettings.php
$wgUploadPath = "[/path/to]/cgi_img_auth.php";

Apache Step 3.2. Edit .htaccess
Edit the .htaccess to look like this

RewriteEngine on RewriteRule ^/path/to/images(.*)$ /path/to/cgi_img_auth.php/$1 [R] RewriteRule ^path/to/cgi_img_auth.php/(.*)$ path/to/cgi_img_auth.php?path=/$1

IIS Instructions
Implementation in IIS is more complex because it lacks the inherent 'pipe' capabilities of Apache or Unix in general. However using a few tricks, IIS can be made to execute the CGI and achieve protection.

WARNING: The img_auth approach ONLY works with the PHP ISAPI mode on the WIMP (Windows, IIS, MySQL, PHP) platform. If you followed the standard windows installation instructions, your wiki will be using CGI (php-cgi.exe) and you will have to convert to ISAPI. Instructions for doing so are in the discussion area. There is a bug in the php-cgi approach in parsing PATH_INFO that will show up as "CGI Error: The specified CGI application misbehaved by not returning a complete set of HTTP headers" on some files in the restricted path. This is a PHP/IIS issue, not a MediaWiki problem.

IIS Step 1. Protect Images Directory from Anonymous Internet Access
With IIS it is important that users cannot access images or files by using alternative URL paths to the bypass the virtual directory redirect. Therefore, a new directory outside the MediaWiki root must be created.

IIS Step 1.1 Create New Physical Directory
Create a new physical directory. This directory should not be inside any other existing web directories or virtual web directories:

Example:

c:\inetpub\wwwroot\MyWikiImg

IIS Step 1.2 Check/Set Directory Security
The Directory security must allow read, write, modify for the Internet Guest Account (usually IUSR_[server name]). Don't worry, you're going to regulate this in subsequent steps.

IIS Step 2. Execute Script img_auth.php for all Accesses to Image Directory
In IIS this is done by creating a virtual directory with the same name as the physical directory (if your directory is off the root web).

IIS Step 2.1 Create Virtual Directory with Same Name as Physical Directory
Create a new virtual directory using Start->Administrative Tools->Internet Information Services (IIS) Manager in the web service you are using for MediaWiki.

Right click on the web service->New Virtual Directory. ..

In the wizard, create a new virtual directory with the same name as the physical directory and point it to that directory.

IIS Step 2.2 Redirect New Virtual Directory to img_auth.php
Still in IIS Manager, right click on the new virtual directory->Properties select the 'Virtual Directory' tab and change the 'The content for this resource should come from:' to 'A redirection to a URL'. Fill in the 'Redirect To:' with the URL to img_auth in your MediaWiki.

Example:

http://wiki.yourwiki.org/MyWiki/img_auth.php

Remember to Click Apply!

IIS Step 3 Copy Old Image Directory to New
Copy the contents of the old images directory ($ip/image) and subdirectories into the new directory you created. Note: The 'image' directory will not exist in the new directory. The new directory should not appear as:

Wrong: MyWikiImg images 0   1    . . . Right: MyWikiImg 0 1  . ..

IIS Step 4.1 Change $wgUploadPath in LocalSettings.php
$wgUploadPath = "[/path/to]/img_auth.php";

Example:

$wgUploadPath = "/MyWiki/img_auth.php";

IIS Step 4.2 Change $wgUploadDirectory in LocalSettings.php
$wgUploadDirectory = "[PhysicalNewDirPath]";

Example:

$wgUploadDirectory = "c:\inetpub\wwroot\MyWikiImg";

IIS Step 4.4 Troubleshoot IIS PATH_INFO
If your installation is not working, it may be because img_auth.php requires the server to return PATH_INFO to know exactly which file you wish to access (eg., everything in the URL after the virtual directory).

There have been several articles and hints that some versions of IIS may disallow the server variables PATH_INFO and PATH_TRANSLATE 'for security reasons'. While we did not have this problem on the current server and patch level (IIS 6.0) it is a noted issue for IIS 4.0 (and possibly prior), you may want to investigate if img_auth.php is not working for you.

The full knowledgebase article may be found at Using PATH_INFO and PATH_TRANSLATED from CGI Applications. The article instructs you on how to run a program written in MS Visual Basic (you may need to load CScript).