Default permissions when using PHP-FPM might not be very safe

interfasys

Verified User
Joined
Oct 31, 2003
Messages
1,821
Location
Switzerland
User files have the following permissions:
user:user

PHP-FPM is configured with the following permissions:
user:user

Typical apps, including the ones installed by CB in /var/www/html have the following permissions:
File 644
Folder 755


That gives the right to PHP to do anything it wants in the folders allowed in open_basedir.
So any attacker who can gain write access through one of the PHP files will be able to wipe the site/app/database, make evil modifications, etc.

Sure, the threat is contained, but it's not very reassuring to the user or the server admin.

What can CB do to fix this? There is only one solution:

Introduce php-<user> groups, one for each user


Things that won't fix anything
  • Using apache as the group in pools
  • Changing permissions


What are your thoughts on this subject?
 
Last edited:
1) Just to clarify, access under /var/www/html should only be done by user "webapps".
If a DA User is accessing /var/www/html as their own privilege, then something isn't setup correctly.

2) That aside, your point may still apply.. in that if (for example) SquirrelMail was compromised, they'd be running as webapps, and could changes SM php files..
Setting the files to 444 would stop "webapps" from changing a webapps owned file... but it would do nothing to prevent a simple chmod change... which then lets them edit them anyway.
So doing a chmod change won't help anything... (unless I'm missing something).

The closest thing to handle that case would be to chown the php files to another User, such as "nobody"..
webapps couldn't touch them in any case...

However, the whole point of having the webapps User is that SquirrelMail needs write access to /var/www/html/squirrelmail/data/* for it's User settings.
Those files would need to stay as they are... and in no situation could we really stop it... without breaking SM itself.

Also, some php types (like suPhp) won't run at all if the php files are not chowned to the correct User. If they're chowned to "nobody", then you'll get an internal server 500 error.

As you've mentioned, in the worst case, they're still contained into the /var/www/html bubble (in regards to "webapps" write access).

John
 
1) Yes, the user for /var/www/html is webapps, I was just giving it as an example. For a vhost it will be /home/user1/domains/dom.com/public_html and user1:user1

2) An attacker could not only change SM files, but also phpmyadmin, roundcube, etc. A modified phpmyadmin login page modification could send every user/password to a remote account per example.

Permissions change solution
You're right about chmod, since the file owner would still be the same as the php user, the attacker simply needs to do a chmod 777 before trying to write to the files he wants to inject his code into...
Maybe it could be added to the list of disabled functions?

User change
Could work for web apps where the server admin can update apps himself and we would need to give group write access to those special folders such as /var/www/html/squirrelmail/data/*. Those folders should only contain non-executable code.
But this would not work for users as files need to be owned by the user.

Group change
PHP user
webapps-php

Files in /var/www/html
webapps:webapps-php

Standard permissions (compatible with most apps)
755/644

Folders/files which need special permissions
775/664

PHP can't chmod files and can only write to files and folders if given permission (like with mod_php).

I see PHP-FPM as a fast PHP with per user settings and better privacy, not as a way to easily write to files so that beginners can install any apps because those have full ownership of all files.

In regards to suPHP, that solution is dying and being replaced by PHP-FPM, so while CB can't just remove that option just yet, because it's probably still used by hundreds, I think it would be good to move forward with a secure and fast PHP. Maybe with a secure_php switch in directadmin.conf?
 
Olivier raises a valid point, basically FPM is more secure from the perspective that the attacker cannot compromise other accounts as they only have write access to one user, however it has a downside that the entire site is writable by the php process, whilst on mod_php only folders with global or group write permissions can be written to.

The few ideas I have are.

1 - run the fpm pool as a different user to the account uid.
2 - add some function into php somehow where it will refuse to write to a folder unless there is global write permissions. Maybe via a php patch?
3 - run all the pools as the apache user basically using same perms structure as mod_php. I dont like this one tho as one of the benefits of FPM is better auditing as processes are tied to user and can also restrict resources better.
 
Olivier raises a valid point, basically FPM is more secure from the perspective that the attacker cannot compromise other accounts as they only have write access to one user, however it has a downside that the entire site is writable by the php process, whilst on mod_php only folders with global or group write permissions can be written to.

The few ideas I have are.

1 - run the fpm pool as a different user to the account uid.
2 - add some function into php somehow where it will refuse to write to a folder unless there is global write permissions. Maybe via a php patch?
3 - run all the pools as the apache user basically using same perms structure as mod_php. I dont like this one tho as one of the benefits of FPM is better auditing as processes are tied to user and can also restrict resources better.
I've played with various ideas and a <user-php> user for a user's PHP-FPM pool is the way to go.
  • Other apps aren't affected because the base unix user is still the same
  • Permissions are managed like with mod_php, so there is plenty of documentation and examples.
  • It's portable (no patching required)
 
I've played with various ideas and a <user-php> user for a user's PHP-FPM pool is the way to go.
  • Other apps aren't affected because the base unix user is still the same
  • Permissions are managed like with mod_php, so there is plenty of documentation and examples.
  • It's portable (no patching required)

I totally agree with Olivier, this is the way to go. Mod Fast Cgi with PHP-FPM should be a good solution. I am going to rebuild my server and was researching on this topic, found this article which i found very informative and sharing it.

http://www.binarytides.com/apache-mpm-php-server-api/
 
Yeah that idea is cool with me as well.

So Martynas and John any comment?
 
A) I think what you've just described is the same idea as the plain old apache + mod_php, with php running as apache.
The moment you allow 777 directories, you've not gained anything, and defeats the purpose of php running as the User.

B) Note that although running php as "apache" is one less layer of protection, there are still good security feature that allow apache+mod_php (uid=apache) to still run securely in a shared hosting environment.
- secure_access group: prevents uid=user from venturing into other folders (doesn't apply to php itself)
- open_basedir: this would be what prevents php from reading files outside of /home/user.
- CB options.conf harden_symlinks_patch: prevents Users from pointing links to files owned by someone else.

So if you decided to go the 777 route, then you might as well use apache+mod_php (uid=apache).

----

C) Idea 2.. if you do want to run php-fpm as some other user, perhaps a unique fpmuser user, per user accounts like for User fred, it could be fred_php.
php-fpm would then run as fred_php.. and then for your tmp/data directories, they could be set to chown fred_php, 700, instead of 777.
That does get a bit messy... and I'm not "suggesting" it, perse, just throwing ideas around :)


----

D) In any case, back to the original ownership of php files in /var/www/html, setting everything to "nobody", except data/write paths, might be an option.
As mentioned, suPhp wouldn't work, as file ownership must match, or it would refuse to run the script, so it would only apply to mod-ruid2+mod-php, or php-fpm, or fastcgi.

John

EDIT: just noticed my point C is the same as the original message, which I missed. So we're on the same page :)
 
Yes 777 is bad, but the difference is with a different user, one would only set 777 on specific folder such as upload or temp, not the entire site for read only folders.

I really think a second php account is the way to go here.

To be clear I am talking about user's public_html folders not the webapps /var/www/html folder. The issue isnt about navigating outside of the sandbox (basedir) but that php-fpm has write access to every file/folder inside the public_html path because it matches the uid owner of the files.
 
Hello,

We migrated weeks ago to php-fpm a DA server (previously on mod_php).

Since then we noticed a highly increase of number of exploited sites (I think 4-5x more cases compared with situation before migration).

I noticed especially many sites having code hacks (new files) uploaded basically in any location (could be even public_html). Before we had no cases of hacks outside of apache writable folders.

This is because of vulnerable code (WP or something else). The point is the DA FPM setup seems to be much more vulnerable than was DA mod_php...
 
Hello! Is this maybe what we should want? Feedback is very appreciated because maybe i'm supposing something stupid here:

PHP permissions
We want PHP to be able to write only to those files and dirs that are really needed (like upload folder). A hacked website can't easily change its own code that way.
For this we used to have the "other" permission on old school mod_php without suphp/modruid. We simply changed for example a uploadfolder that had to be writable from 755 to 757 or 777. The problem then was that technically other users and services could edit/remove that file.

If we run php-fpm by default this is done under the owner of the files. It gives the security that other users and services can't edit anything. But for the own PHP process editing the files/dirs is possible by default. There isn't an easy way to fix it by changing the permissions. Php-fpm is the owner and thus can change the permissions back.

To change this and get the best form both worlds we will run php-fpm under a seperate "php" user. So user john now also gets a user called john_php that will be used by php-fpm.

We will keep the group that php-fpm runs under, the same (john). So we can then change the group permission to writable if it is desired. The default permissions will still be sane and in fact exactly what we want.

In some cases you may want i.e. Wordpress to be able to update itself. In that case you can still chmod all files to 664 and folders to 775.
But in most cases you now just elevate group permissions (the second digit). So a file gets 664, or a dir gets 775 if you really want PHP to have write access to it.

NOTE: Already existent users wont get touched by this script. Please do the steps manually. In the future we will create a script that can be used for this.

nano /usr/local/directadmin/scripts/custom/user_create_post.sh

and paste this content:

#!/bin/sh

# add a new user for php-fpm to run on
useradd -r -s /bin/false -d / "$username"_php

# change the user fpm runs under to the new one
sed -i "/^user/c\user = \$pool_php" /usr/local/directadmin/data/users/$username/php/php-fpm55.conf

# restart fpm to take effect of changes
service php-fpm55 restart &> /dev/null

# make sure php is allowed to traverse up to the documentroots
if [ "$usertype" = "reseller" ] || [ "$usertype" = "admin" ]; then

# this is a special user so we need to chmod the domains folder
chmod 711 /home/$username/domains

else

# this is a standard user so we need to chmod the main folder
chmod 711 /home/$username

fi

echo -e "Successfully implemented a separate user for php-fpm for added security.<br>Elevate group permissions of a file to 664, or a dir to 775 if you really want PHP to have write access to it!"

exit 0

chmod 750 /usr/local/directadmin/scripts/custom/user_create_post.sh


nano /usr/local/directadmin/scripts/custom/user_destroy_post.sh

#!/bin/sh

userdel "$username"_php
echo -e "Successfully removed the extra user for php_fpm"

exit 0


chmod 750 /usr/local/directadmin/scripts/custom/user_destroy_post.sh
 
update

I would have been very interested in others opinions because I work on my own and can really use a objective look at the code. I've been using it more than a year now and it works great. I have a small change though that is needed for the sake of persistency so here is the updated how to:

STEP 1 - we have to edit the template file via custom folder like this (Or else ./build rewrite_confs will remove the custom edits):
Code:
$ mkdir /usr/local/directadmin/data/templates/custom/; cp /usr/local/directadmin/data/templates/php-fpm.conf /usr/local/directadmin/data/templates/custom/ && sed -i "/^user/c\user = \$pool_php" /usr/local/directadmin/data/templates/custom/php-fpm.conf


STEP 2 - Now we must take care that php_user get created and deleted upon creation / deletion of DA user.

Code:
$ nano /usr/local/directadmin/scripts/custom/user_create_post.sh

and paste this content (or ad it to existing code in a logical way):

Code:
    #!/bin/sh

    PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin

    # add a new user for php-fpm to run on
    useradd -r -s /bin/false -d / "$username"_php

    # restart fpm to take effect of changes
    service php-fpm56 restart &> /dev/null

    # make sure php is allowed to traverse up to the documentroots
    if [ "$usertype" = "reseller" ] || [ "$usertype" = "admin" ]; then
       
        # this is a special user so we need to chmod the domains folder
        chmod 711 /home/$username/domains

    else
       
        # this is a standard user so we need to chmod the main folder
        chmod 711 /home/$username

    fi

    echo -e "Successfully implemented a separate user for php-fpm for added security.<br>Safest permissions are 644 for files and 755 for dirs (although 444 and 555 would work also). Elevate permissions of a file to 664, or a dir to 775 if you really want PHP to have write access to it but still keep others out!"

    exit 0

make it executable

Code:
$ chmod 750 /usr/local/directadmin/scripts/custom/user_create_post.sh

now we must make sure the extra user gets deleted if the DA user gets deleted


$ nano /usr/local/directadmin/scripts/custom/user_destroy_post.sh

and paste this

Code:
    #!/bin/sh
    PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin

    userdel "$username"_php
    echo -e "Successfully removed the extra user for php_fpm"

    exit 0

make it executable

Code:
$ chmod 750 /usr/local/directadmin/scripts/custom/user_destroy_post.sh

Please let me know if you have any feedback or ideas.
 
Back
Top