Page 1 of 1

Uploading files

Posted: Fri Nov 30, 2007 3:24 pm
by alex.barylski
When uploading files and assuming your PHP is running under Apache user: nobody or apache. How do you ensure the security of the files system?

In order to allow PHP to upload a file and move it into a directory which is created by PHP shortly after upload, having a permission 777 is not good for safety.

775 is no better because then PHP can move files into the directory and/or edit/delete, etc.

Do you:

1) Run PHP as it's own user or use phpsuexec
2) Use FTP functions to change the permissions to 777 when uploading and back to 775 when finished?

The later is probably the best choice for widely distributed PHP applications, although I will likely have complete control over this environment.

Incase I missed a technique or a detail, what do you all think?

Posted: Fri Nov 30, 2007 3:26 pm
by infolock
You should only put files that are uploaded via a form to a non-http accessable directory.

In other words, upload them to /usr/local/www/my_uploads instead of /usr/local/www/htdocs/my_uploads

Then, when you are doing, move it to a directory that has like 766 or 755 or whatever. That's one quick step.

The next thing to do is check the header information and ensure that the file they are trying to uploads matches the file type you are expecting (img, txt, etc).

There are a million other things. I'm sure the others can shed more light on the subject.

Posted: Fri Nov 30, 2007 4:00 pm
by alex.barylski
infolock wrote:You should only put files that are uploaded via a form to a non-http accessable directory.
That is one alternative, but unfortunately not available to me. I need the files accessible by web server and using a proxy script isn't an acceptable solution. Basically I need read only access to the files but my PHP scripts need write access, which complicates things, because PHP (in my case right now anyways) is running under user: Apache.

I'm wondering if I could just use some shell scripts which wrap native commands invoked by PHP through exec() to carry out moving files, deleting and creating file and directories...

If the shell scripts are "owned" by a user say "shell" then when invoked via exec:

Code: Select all

exec('createdirs.sh');
exec('deletedirs.sh /uploads');
exec('movefiles.sh /tmp /uploads');
When they created the folders as 755 any files moved into those directories via movefiles.sh would then only be readable by apache/PHP and not writable. Can I not achieve something like this using the SETUID flag under the permissions for each shell script???

Cheers :)

Posted: Fri Nov 30, 2007 4:24 pm
by feyd
Care to explain why a proxy script is not acceptable?

Posted: Fri Nov 30, 2007 5:28 pm
by alex.barylski
I might have to go that route...but...

1) I may not always have access to outside of the docroot.
2) I have two folders which hold images and generic files. I glob those files and display them in a list inside a WYSIWYG, etc. When people edit the HTML which references those resources I would have to now find the file references and replace the URL with the proxy script instead. PITA essentially and additional processing.

Those two reasons had me seek an alternative. I thought originally I could use some shell scripts run under a different user, but now it seems that most *nix distro's frown upon that and don't actually obey the setuid flag on shell scripts - only executables.

My other alternative is to consider running PHP as CGI/PHPSUEXEC...this is the direction I think I will move in as it won't require substantial changes to existing source - hopefully.

Posted: Fri Nov 30, 2007 5:38 pm
by feyd
Who says you have to replace the references to the files with the proxy script call?

Posted: Fri Nov 30, 2007 5:43 pm
by alex.barylski
Well all the paths are currently:

Code: Select all

var/www/somedomain.com/uploads/images/
http://somedomain.com/uploads/images/logo.gif
If I move those files into:

Code: Select all

var/www/uploads/
Obviously the files will be broken.

I suppose I could use mod_rewrite to to convert requests into a proxy.php script, such that:

Code: Select all

proxy.php?file=var/www/uploads/
Is that what you were hinting at?

Cheers :)

Posted: Fri Nov 30, 2007 5:48 pm
by feyd
Hockey wrote:I suppose I could use mod_rewrite to to convert requests into a proxy.php script, such that:

Code: Select all

proxy.php?file=var/www/uploads/
Is that what you were hinting at?

Cheers :)
Yes.

Posted: Fri Nov 30, 2007 6:04 pm
by alex.barylski
Sweet. That will actually work. :)

Can you tell me how to adjust the following mod_rewrite code I dug up:

Code: Select all

RewriteEngine on
RewriteBase /
RewriteRule ^blog/(.*)$ blog/$1 [L]
RewriteRule !\.(gif|jpeg|jpeg|cgi|js|ico|gif|jpg|png|css)$ index.php
This apparently feeds all requests through a front controller *except* when inside a directory called "blog". I need the opposite. I need everything to be ignored *except* anything inside an "uploads" directory. In which case I need to forward the request as well as the URL of the file onto proxy.php.

Then inside the proxy I guess I just check the extension, set the approriate headers and send back as a blob?

Posted: Fri Nov 30, 2007 7:45 pm
by feyd
If you put an .htaccess in the uploads folder, that alone will segregate the rewrite to only work against it. I bet you can figure out how to forward the request information from there... ;)