DekGenius.com
[ Team LiB ] Previous Section Next Section

Recipe 6.21 Protecting Files with a Wrapper

Problem

You have files to which you want to limit access using some method other than standard web authentication (such as a members-only area).

Solution

In httpd.conf, add the following lines to a <Directory> container whose contents should be accessed only through a script:

RewriteEngine On
RewriteRule "\.(dll|zip|exe)$" protect.php [NC]
RewriteCond %{REMOTE_ADDR} "!^my.servers.ip"
RewriteRule "\.cgi$" protect.php [NC]

And an example protect.php that just displays the local URI of the document that was requested:

<?php
/*
 * The URL of the document actually requested is in
 * $_SERVER['REQUEST_URI'].  Appropriate decisions
 * can be made about what to do from that.
 */
Header('Content-type: text/plain');
$body = sprintf("Document requested was: %s\n", $_SERVER['REQUEST_URI']);
Header('Content-length: ' . strlen($body));
print $body;
?>

Discussion

In the situation that prompted this recipe, authentication and authorization were completed using a cookie rather than the standard mechanisms built into the web protocols. Any request for a document on the site was checked for the cookie and redirected to the login page if it wasn't found, was expired, or had some other problem causing its validity to be questioned.

This is fairly common and straightforward. What is needed in addition to this is a way to limit access to files according to the cookie and ensure that no URL-only request could reach them.

To this end, a wrapper is created (called protect.php in the Solution), which is invoked any time one of the protected document types is requested. After validating the cookie, the protect.php script figures out the name of the file from the environment variables, determines the content-type from the extension, and opens the file and sends the contents.

This is illustrated in the Solution. Any time a document ending in one of the extensions .dll, .zip, .exe, or .cgi is requested from the scope covered by the mod_rewrite directives, and the request comes from some system other than the web server system itself (i.e., from a client system), the protect.php script will be invoked instead. In the Solution, the script simply displays the local URI of the document that is requested; applying additional access control or other functionality is easily developed from the example.

If access control is the main purpose of the wrapper and the access is granted, the wrapper needs to send the requested document to the client. In this case, the wrapper could either determine the filesystem path to the desired document and use the PHP routine fpassthru( ) to open it and send it to the client, or it could access the document using PHP's ability to open a URL as though it were a file with the fopen(http://docurl) function call. (This latter method is necessary if the document requires server processing, such as if it's a script.)

This would ordinarily trigger the wrapper on the dynamic document again, causing a loop. To prevent this, the wrapper is only applied to dynamic documents if the requesting host isn't the server itself. If it is the web server making the request, we know the wrapper has already been run and you don't need to run it again. The server processes the document as usual and sends the contents back to the wrapper, which is still handling the original request, and it dutifully passes it along to the client. This is handled by the RewriteCond directive, which says "push requests for scripts through the wrapper unless they're coming from the server itself."

This method is perhaps a little less than perfectly elegant and not the best for performance, because each CGI request involves at least two concurrent requests, but it does address the problem.

See Also

    [ Team LiB ] Previous Section Next Section