Permissions for files created by the user and PHP - php

So I have a user foo and the group www-data When the user creates a file/directory manually the permissions are:
foo:www-data --> rwx:r-x
And the user can then do what they like with that file/directory.
But when I use PHP to create a file or directory the permissions generated are
www-data:www-data --> rwx:r-x
Which then doesn't allow the user to do what they like with that file/directory.
So I have two options:
I have thought about adding the user foo to the group www-data but I have multiple virtual hosts and I don't want them to be able to edit each other's virtual domains (if that is even possible?!)
I have also thought about when creating the folder using PHP I will set the permissions to 777 but that seems like a big 'no no' (is it?)
What should I do?!

What you actually want to do is run different virtual hosts as different users. This is a link to some helpful answers for nginx:https://serverfault.com/questions/370820/user-per-virtual-host-in-nginx
The same concepts apply to Apache.
Edit:
The answers weren't clear to me when I read them, and there's a lot of info in the comments. The second answer by #Ricalsin is very informative and had a link that I used. Be sure to restart php-fps and nginx!

You could use phps chown() function to change the owner after creating the directory. See http://php.net/manual/en/function.chown.php. But you may need special privileges to successfully use the function, which may introduce a security issue.
Another option is the use of suEXEC in combination with SuexecUserGroup if you are running php-fpm (via FCGI instead of mod-php). In your virtual host file you will have to assign a user and a group to a virtual host via
SuexecUserGroup exampleuser examplegroup
With this directive activated all new directories and files created by php will have the specified user/group combination. Thats how a known webhost from germany does this, see the uberspace documentation (german only). More general information can be found here.
Using this solution you would avoid many security risks automatically. No need for 777 permissions, no possibility to see each others files etc.
Because with this approach, every user will have his own php instance running, its very easy and secure to allow them to use different php interpreter versions or own php.ini files.

Related

Prevent Apache/PHP from running code that affects another vHost

THE SITUATION
I have multiple folders in my /var/www/ directory.
Users are created that have control over a specific directory... /var/www/app1 belongs to app1:app1 (www-data is a member of the app1 group).
This works fine for what I want.
THE PROBLEM
If the app1 user uploads a PHP script that changes the file/folder permissions for something in app2s directory structure, the Apache process (as there's only one installed on the server) will be more than happy to run it, as it has the necessary permissions to access both /var/www/app1 and /var/www/app2 folders and files.
EDIT:
To the best of my knowledge, something like, /var/www/app1/includes/hack.php:
<?php
chmod("/var/www/app2", 777);
?>
The Apache process (owned by www-data) will run this, as it has permissions to change both /var/www/app1 and /var/www/app2 directories. The user app1 will then be able to cd /var/www/app2, rm -rf /var/www/app2, etc., which is obviously not good.
THE QUESTION
How can I avoid this cross-contamination of the Apache process? Can I instruct Apache to only run PHP scripts that affect the files/folders that reside within the relevant vHost root directory and below?
While open_basedir would help, there are several ways of bypassing this constraint. While you could break a lot of functionality in php to close off all the backdoors, a better solution would be to stop executing the php as a user whom has access to all the files. To do that, you need to use php-fpm with a separate process pool/uid/gid for each vhost.
You should still have a separate uid for the php execution from the uid owning the files with a common group allowing a default read only access to the files.
You also need to have separate storage directories for session data.
A more elaborate mechanism would be to use something like Apache traffic server in front of a container-per owner with each site running on its own instance of Apache - much better isolation, but technically demanding and somewhat more resource intensive.
Bear in mind, if you are using mariadb or similar, that the DBMS can also read and write arbitrary files (SELECT INTO OUTFILE.../LOAD DATA INFILE)
UPDATE
Rather than the effort of maintaining separate containers, better isolation could be achieved with less effort by setting the home directory of the php-fpm uid appX to the base directory of the vhost (which should contain, not be, the document_root - see below) and use apparmor to constrain access to the common files (e.g .so libs) and #{HOME}. Hence each /var/www/appX might contain:
.htaccess
.user.ini
data/ (writeable by fpm-appX)
html/ (the document root)
include/
sessions/ (writeable by fpm-appX)
You should add an open_basedir directive to each site's vhost file. The open_basedir directive limits the directories that a site can access.
You can read more about open_basedir here.

Apache/CentOS 7: /var/www/html/ owned by root but created files owned by apache - how do I resolve this?

I have a fresh, unmodified install of Apache on CentOS 7. I notice that when I look at the folder permissions for /var/www/html it and it's content is owned by apache. When a file is created, however, its owner and group is Apache.
Though html is owned by root:root, should all of the contents be owned by apache:apache? or [user]:apache with that user belonging to the Apache group? How should I go about this?
Edit:
Another question - do I want to change this? I do not have a very good understanding of file ownership in Linux systems but it seems with this configuration that the newly created files (apache:apache) are prevented from taking action against files that already exist (root:root). This should prevent PHP hacks from being able to manipulate any existing files, right? Is this just the illusion of security though?
Check your /etc/httpd/conf/httpd.conf file and search for user and group [e.g. User apache Group apache]. Those are the owners by default. In your website there is no need too add write permissions for files and folders assigned to user:group, but you can set readable by owner and others in order to be accessible via web.
Updated answer:
The main reason DirectoryRoot (/var/www/html) owned by root is security. You can leave root as owner of files and set group to apache. Regarding security you make sure apache group has read-only access to files [-> One first meassure]. The security is not an illusion. While files are owned by root and do not have rw access from others, it is hard for external attackers to gain write access to files [because this is the most common way to hijack a site].

Differentiate each apache user and give permissions

In a web application, I want to create a folder for each www-data user and give write permissions just on that folder, and just to that user.
AFTER VALIDATION I can do:
mkdir($file->getPath().mt_rand(0,100000),0700);
This will create a new directory with a random name, in the path $file->getPath() with all permissions to the owner user. But it would give permissions to all www-data users.
If I create a chroot jail I have to copy all files again for each user, because I should create many jails (one for user).
I'm getting crazy with that and don't find out the solution.
If I understand your question right, your problem begins with the structure of the linux permission/user framework. Thus, the Apache process owning user is the one that is creating dirs and files when it is running your script.
If you need user separation for scripts, e.g.: you have different directories for different (virtual) hosts on your server and you don't want the script of one host is acting on data of a different host on the same (apache) server, then you should use 'mpm_itk_module' instead of the more common 'mpm-prefork' apache.
Using this you can go and define the user/group that apache is using when it executes any scripts and e.g. creates directories just by this command for each virtual host entry in the httpd.conf:
<IfModule mpm_itk_module>
AssignUserId USER GROUP
</IfModule>
If you really want to create different directories from ONE script execution, you need the apache process to be owned by root.root and then the script needs to set the permissions and owners for each directoy the way you want.
But it is never a good idea to run even the best scripts on a webserver as root, as you might fail to think of any risk.
The user/right separation by vhosts seems to be a much saver way in my view.
Another point - PHP only - is suPHP -> http://www.suphp.org
EDIT:
Ok, I had a look at your site and even if I can't speak spanish, it looks like you have just one website, acting for different users coming allways thru this webpage. So where is the need for user separation on linux filesystem permissions? You can restrict everything by your application with no need for filesystem users. Even if you give e.g. additional ftp access - restrict it e.g. with proftpd it has its own chroot mech for different users.
You should have to care about filesystem rights only if you can't control who is executing what. Thats a common problem on a multidomain host which you could solve with the mpm_itk_module I mentioned.
Maybe you should describe your situation a little bit more?
EDIT 2:
As suggest in the coment, if you ONLY use apache to give the users access to the files for uploading/manipulation, then just put the files outside(!) the documentroot tree of apache and create simple database to know which file is owned by which user:
user a | file parentdir/filename
This could be an easy table and your php code gives a list to the user from the database which file he is able to see/manipulate and your code does the work as intended by the user action.
As long as you don't give the user access to the files by other services (ftp, ssh, etc.) there is NO need to work with linux user rights at all. Just take care to place the files outside the documentroot of the server so that only your php code has access to the files by the rights of the apache user of your server.
EDIT 3:
Haha, now finally I got your problem after I read a similar post of you: (How can an Apache user write files when having permissions to do it?)
In this case (with REALLY anonymous users on your webpage) you have NO chance to solve this at all. Every visitor is handled as the same one without authentication. And as I assumed in my last EDIT and commented in the similar post: no need to handle with linux file permissions at all.
YOUR SOLUTION ;) :
You need to do the file manipulation in one sessions with session-ids while the user is visiting your page. So your code needs to handle the relation between the visitor (the session-id) and the file he uploaded with this session-id. Using a session-id that is valid as long the visitor is online is the best way to do this. And again - no need for filesystem permissions.... ;)
The second way is with authed users as suggested before: Create a db table with users/passwords to login the webpage (not the server) and another table that holds the user/file relations. Than, after he logs into the webpage, work again with sessions to allow the user accessing/manipulate already uploaded files.
I can that you run apache with mod_php. So then it means that your PHP instance work under apache instance and have apache USER and GROUP. You can create folder and can change owner of this folder but owner must be user in you system (not apache or same virtual user).
But you can store in every directory file for example ".permitions" and put inthat file virtual owner. Next you need filter every write (delete,rename, etc...) attempt to this directory and compare your virtual user and user that stored in .permitions file.
Sample Class (not full but it is more than enough to understand idea):
class UserDirs {
private $path='/home/vusers';
public function mkdir($user){
$d = $this->path.'/'.md5($user);
mkdir($d);
file_put_contents($d."/.owner",$user);
}
public function checkOwner($user, $dirname){
$f = $dirname."/.owner";
$virtual_owner = file_get_contents($f);
return $user === $virtual_owner;
}
}
$d = new UserDirs()
$d->mkdir("foo","bar");
echo $d->checkOwner("foo1","bar") === true ? "OK":"FAIL";
echo $d->checkOwner("foo","bar") === true ? "OK":"FAIL";
You can encapsulate all that you need in this class to work with UserDirs and extend class depending your requirement.
Your users do not have system accounts. It probably is not feasible to create those accounts either. Therefore, I'd recommend managing all of this via the Web UI.
Continue to create your directories as you are. The permissions are fine. Your user interface needs to change though, to only show that user's directory or files. I assume you have a database associated with this page. Associate the usernames and the randomly generated directory name with the user. If someone attempts to go to the direct path and they are NOT the user associated with that directory, kick them back to the login screen.
To illustrate, I created an account named test and was presumably given a unique directory. If I log out, I should not be able to visit that directory because your code would see that
I'm not logged in and therefore don't have access to that directory
If I were to login as test2 and visit the directory of test, your code should see that
I'm not the owner of the directory being visited and should therefore be redirected as appropriate.
You need to add a function that checks the directory the user is visiting and compare it to the directory associated with the user. If they two match, allow them to proceed. If they don't match, redirect the user.

Folder permissions when telling PHP to save a file to that folder?

I'm trying to use this Dagon Design PHP form to help a local non-profit publication enable their readers to submit photos. I've got the "mailer" part working -- the notifications work fine -- but the "saving a file to a folder" part isn't functioning.
On the form page, the author says "the directory must have write permissions," but I'm not sure "who" is writing to that folder -- is this PHP script considered "Owner" when it saves something on my site? Or do I need to allow save permissions for Owner, Group and Others?
I'm not sure why the script isn't saving the photos, but this seems like a good place to start. I've tried looking around on Stack for answers, but most questions seem to have to do with folder creation/permissions.
The page I'm clumsily trying to build is here, if that helps.
As Jon has said already, you don't want to allow write access to everyone.
It's also possible (depending on the hosting) that something like suEXEC is being employed - which will cause your PHP script to run as a user other than the webserver's (as reported by Dunhamzzz).
Probably your best approach, in my opinion, is a script calling whoami:
passthru('whoami');
Or alternatively you could try:
var_dump(posix_getpwuid(posix_geteuid()));
Bear in mind, this does give system information away to the world - so delete the script once you've used it!
Then, as you've correctly asserted in your question, it'll likely be the file permissions.
If you do have CLI access, you can update the permissions safely as so (first command gets the group)
id -n -g <username>
chmod 770 <directory>
chown <username>:<group> <directory>
(You may have to pre-pend "sudo" to the "chown" command above, or find other means to run it as "root"..., reply back if you get stuck.)
If you've not got access to run command-line, you'll presumably be doing this via a (S)FTP client or the alike. I'm afraid the options get a little to broad at that point, you'll have to figure it out (or reply back with the client you're using!)
As always, YMMV.
Finally, bear in mind if this is your own code, people will at some point try uploading PHP scripts (or worse). If that directory is accessible via a public URL ... you're opening the hugest of security holes! (.htaccess, or non-document root locations are your friend.)
If you are not sure how is your server configured (and this would influence who's the final file owner) then add write permission to anyone (chmod a+w folder), upload one file and ls -l to see the owner. Then you can adjust permissions to allow write access to certain users only
The PHP script that saves the files is running with the privileges of some user account on the server; the specific account depends on your OS and the web server configuration. On Linux and when PHP is running as an Apache module this user is the same user that Apache runs as.
Solving your problem reduces to determining which user account we are talking about and then ensuring that this user has permission to write to the save directory (either as owner or as a member of the group; giving write access to everyone is not the best idea).
You'll need to set the permissions of the directory to that of the webserver (probably Apache, nginx or similiar), as that's what is executing the PHP.
You can quickly find out the apache user with ps aux | grep apache, then you want to set the permssions of the upload directory to that user, something like this:
chown -R www-data:www-data images/uploads

How can I allow php to create files with the same ownership as the files that created them?

PHP creates files with apache:apache ownership which seems to be causing issues with other php scripts accessing the file.
How can I allow php to create files with the same ownership as the files that created them?
I've read elsewhere that having safe_mode turned on can affect this but I've turned it off and reuploaded the files and i still get the same issue.
I'm sure this will be a simple question for someone more familiar with apache but I've failed to find the solution by searching around.
Thanks
If ownership matters and multiple users / projects are on the same server, you might want to look into SuExec in Apache: PHP files will then be run by the user indicated in the settings, so default ownership of files is automatically taken care of. It saves a lot of chown/chmod'ing, and the processes run by the user are more easily restricted.
Otherwise, I normally create a group with both the owner & apache, and set the default umask to 007.
If you are using a Windows OS you can start Apache as a service and allow apache to use your own account's permissions when starting.
Try using fileowner ( http://www.php.net/manual/en/function.fileowner.php ) to get the id of the owner of the current script, posix-getpwuid to get the username for that id ( http://www.php.net/manual/en/function.posix-getpwuid.php ) and chown ( http://php.net/manual/en/function.chown.php ) to set the user for the files.
Why go through all the programatic hassle to change the owner? apache.apache is a very insecure owner anyway. Why not just chmod 0777 the file providing read, write, and execute to all owners. This will eliminate the issue.
If you are still having troubles, then you may need to check if open_basedir is on. If that is the case, it is not file ownership or permissions, but location. This basically means you need to put the file in a location that apache/php already has included in their path.
A.M. mentioned chown() above, please be aware that generally chown() can only be used by root and your webserver running account is highly unlikely to be root, that's a very bad idea.
It is possible to setup sudo to allow chown by other users in specific areas and only to specific users. Just have to create a suitable entry in /etc/sudoers, usually by using the visudo program. If you do not have root access yourself, then your hosting provider will have to do this for you, if they will.
For more information: http://www.sudo.ws/sudo/sudo.html

Categories