Forum Moderators: coopster

Message Too Old, No Replies

Reading files below the web root

         

ryan_b83

12:54 am on Mar 9, 2007 (gmt 0)

10+ Year Member



Hello, I have been tring to make a script that can read my "new mail" directory which is below the web root. I have a simple script that reads a directory and dumps the files in it ot the screen. It works fine for files inside the web tree, but i cannot read files below? Is there something i need to do to allow this? Is this a security issue?

thanks,
ryan

cmarshall

1:30 am on Mar 9, 2007 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



It is almost certainly a security issue.

You need to figure out what user the PHP uses (I don't think that PHP uses httpd, which is the Apache daemon), then give that user permission to read and/or write the directory in question.

dreamcatcher

8:13 am on Mar 9, 2007 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



A relative path from your public root should allow you to access a file outside the web root via a script.

include('../file.php');

dc

drooh

10:42 am on Mar 9, 2007 (gmt 0)

10+ Year Member



what if you wanted to link to a video or mp3 file? how would you do that?

phranque

10:59 am on Mar 9, 2007 (gmt 0)

WebmasterWorld Administrator 10+ Year Member Top Contributors Of The Month



what if you wanted to link to a video or mp3 file? how would you do that?

you could link to a server side script that reads the media file from the non-web-accessible directory and serves it with the correct response headers for MIME type, etc.

cmarshall

11:28 am on Mar 9, 2007 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



I just got finished writing an action that does exactly this for the intranet wiki we use at work. It is a way of uploading files securely.

It uses two files: One is an action file that generates code to be placed in rendered pages, the other is a "fetcher," that is called as if it were the file. It checks the security creds of the caller, and, if they have the rights, it fetches the file from outside the HTTP tree, changes the MIME type, and sends it to the caller as if they had directly linked the file. Works for any kind of file. I just output an appropriate content-type header.

phranque

11:50 am on Mar 9, 2007 (gmt 0)

WebmasterWorld Administrator 10+ Year Member Top Contributors Of The Month



and usually you want to send a http 404 response but no html error document if the file doesn't exist.

cmarshall

1:06 pm on Mar 9, 2007 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Good point. I'll do that. Thanks!

drooh

6:33 am on Mar 11, 2007 (gmt 0)

10+ Year Member



would any of you be willing to provide some code examples of how to perform an opperation like this?

so far I am able to read contents of a text file but if I am trying to link to an image or media file I render errors.

cheers...

cmarshall

1:39 pm on Mar 11, 2007 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



This has been transmuted from a dedicated file to a more generic one for your listening pleasure. It won't work on my system, but should give you an idea of how it works.

When a file is uploaded, it has its name changed to protect the guilty, and a DB record is made with the original name and MIME type. The generically renamed file is stored out of the root in a subdirectory keyed on the Wiki page name. You can't tell what the file was by looking at it. You need to open it and root around to figure that out. Just a little bit of extra misdirection.

When we download the file, the wiki checks the user's credentials and clears or denies the user for that file. We then restore the filename and MIME type when we fetch the file for the user.


<?php
if ( isset ( $_GET['get_file'] ) && intval ( $_GET['get_file'] ) )// I use GET, because I check the session/cookie
{
require_once ( "user_verify_tools.php" );// Loads all kinds of wiki stuff

function DownloadFile ( $thisObj )
{
define ( "_SECURE_DIRECTORY_ROOT_", "../secure_filedir" );// Outside the HTTP root

$query = "SELECT * FROM stored_secure_files WHERE _id='".mysql_real_escape_string(intval ( $_GET['get_file'] ) )."' LIMIT 1";

$result = mysql_query ( $query );// Actually, I use built-in functions for this, not straight mysql

if ( $result )
{
$row = mysql_fetch_array ( $result );
if ( $thisObj->HasAccess ( 'read', $row['_page_id'] ) )// Uses internal wiki test against the user's cookie.
{
$src_file = _SECURE_DIRECTORY_ROOT_."/".$row['_page_id']."/file_".$result['_id'];
header("Content-type: ".$row['stored_mime_type']);
header("Content-Disposition: filename=".$row['stored_filename']);
readfile($src_file);
}
else
{
header("HTTP/1.1 401 Unauthorized");
}
}
else
{
header("HTTP/1.1 404 Not Found");
}
}

DownloadFile ( $global_wiki_object );
}
?>