Phith0n 2014/08/25 moreover

0 x00 background


As we all know, virtual host security is not good to do, especially to prevent cross-directory has become the focus. Apache + PHP server to prevent cross-directory way is relatively simple, all mature web hosting solutions are based on Apache, such as DirectAdmin, CPanel.

But now is not the age of Apache, in Linux +nginx+mysql+ PHP how to prevent different virtual host cross-site?

First we need to understand how Nginx works, and then we’ll figure out how to do it. The clouds have a very good article drops.wooyun.org/tips/1323 knowledge database, introduces the security configuration of nginx, everyone can see.

Nginx is really just a reverse proxy server. It receives the request and looks to see if the current request is a.php file. If so, it forwards the request to phP-FPM for processing and sends the result to the user. So there are two permissions to consider: the first is the nginx permissions and the second is the PHP-fPM permissions. As shown below, both Nginx and PHP-FPM read this file, so permission assignment is an important consideration.

There are three defense cross-site defense, the first is to prevent other users column site directory, to prevent some of their sensitive file names to be seen and access; Second, prevent other users from reading their own files to prevent configuration information leakage. The third is to prevent other users from writing shells in their own directories.

PHP has clearly taken this issue into account. Open_basedir in its configuration file is a directory list that only PHP is allowed to access. By setting this open_basedir we can prevent PHP from reading or writing files outside the web directory, such as /etc/passwd.

The problem is that open_basedir is a configuration file written in php.ini, and all virtual hosts use the same PHP. We can prevent PHP from accessing files outside the Web directory, but we can’t prevent “virtual host 1” from accessing files in “virtual host 2”. Because both are in the Web directory. An even bigger problem is that many versions of PHP open_basedir are unreliable and can be easily bypassed.

This is the problem now. The solution is to have each virtual host start phP-FPM separately with a different user.

To implement the above method, we need to make some changes to the installed LNMP. (I use is the domestic use of a relatively wide “LNMP one key installation package”).

0 x01 lNMP reinforcement


For example, we have two virtual hosts game01.com and game02.com on our server. The directories are /home/wwwroot/game01/ and /home/wwwroot/game02/ respectively.

The new LNMP one-click installation package has built-in cross-site protection, because after PHP 5.3.3, you can add statements like the following at the end of php.ini:

[HOST=www.vpser.net] 
open_basedir=/home/wwwroot/www.vpser.net/:/tmp/ 
[PATH=/home/wwwroot/www.vpser.net] 
open_basedir=/home/wwwroot/www.vpser.net/:/tmp/
Copy the code

You can assign different open_basedir to different hosts. However, we do not use this method here. Firstly, it limits THE PHP version above 5.3.3, and secondly, open_basedir also has limitations and vulnerabilities, so we cannot rely on it completely. So, virtual host to create good later, came to/usr/local/PHP/etc/PHP. Ini the content commented out. (comment;)

First, let different VMS run different PHP-fpm:

Create a phP-fpm. pid file for each site

cd /usr/local/php5/var/run
touch php-fpm-game01.pid
touch php-fpm-game02.pid   
Copy the code

Create a php-fpm.conf file for each site

cd /usr/local/php5/etc/ 
cp php-fpm.conf php-fpm-game01.conf 
cp php-fpm.conf php-fpm-game02.conf     
Copy the code

Sock file for each site

Sock # set file owner to WWW (must be consistent with nginx user) touch /tmp/php-cgi-game02.sock chown www.www /tmp/php-cgi-game02.sockCopy the code

4. Modify relevant documents

vi /usr/local/php5/etc/php-fpm-game01.conf 
pid = run/php-fpm-game01.pid 
listen =/tmp/php-cgi-game01.sock; 

vi /usr/local/php5/etc/php-fpm-game02.conf
pid = run/php-fpm-game02.pid
listen =/tmp/php-cgi-game02.sock; 

vi /etc/init.d/php-fpm 
vhost=$2 
php_fpm_CONF=${prefix}/etc/php-fpm-$vhost.conf 
php_fpm_PID=${prefix}/var/run/php-fpm-$vhost.pid 
php_opts="-d open_basedir=/home/wwwroot/$vhost/:/tmp/ --fpm-config $php_fpm_CONF"
Copy the code

$vhost = /home/wwwroot/$vhost/:/ TMP /. $vhost = $2 (game01 or game02).

Continue to modify

Vi/usr/local/nginx/conf/vhost/game01.com.conf # profile name may not be the same, according to the actual situation to change fastcgi_pass Unix: / TMP/PHP - cgi - game01. The sock. vi /usr/local/nginx/conf/vhost/game02.com.conf fastcgi_pass unix:/tmp/php-cgi-game02.sock;Copy the code

5. Add boot options

vi /home/start.sh # ! /bin/bash auto=$1 /bin/bash /etc/rc.d/init.d/php-fpm $auto game01 /bin/bash /etc/rc.d/init.d/php-fpm $auto game02 chmod +x /home/start.shCopy the code

Then edit /etc/rc.local to add start.sh to the boot option. At this point, different virtual hosts will run different PHP-FPM. We also need to run with different user identities.

groupadd game01 groupadd game02 
useradd game01 -M -s /sbin/nologin -g game01 
useradd game02 -M -s /sbin/nologin -g game02     
Copy the code

Added game01. Game01 and game02. Game02. Modify/etc/usr/local/PHP/PHP – FPM – game01. Conf:

listen.owner = game01
listen.group = game01 
user=game01 
group=game01     
Copy the code

The same is true for Game02. So we let php-fpm run as a different user.

/home/wwwroot/

cd /home/wwwroot/ 
chown game01.game01 -R game01 
chown game02.game02 -R game02   
Copy the code

Give the game01 and Game02 folders to users Game01 and Game02, respectively.

In addition, nginx runs as WWW user by default, so game01 and game02 files cannot be read. If you set the file permission to 777, game01 will not be able to read game02 files.

Therefore, we should add WWW users to game01 and game02 groups, and set the game01 and game02 files to 750 privileges. This will allow WWW to read the game01/game02 files (because in the same group, and the group permissions are 5,5 is enough). It also prevents Game01 from reading game02’s files.

Linux allows you to add a user to multiple groups, so here’s how:

usermod -aG game01 www 
usermod -aG game02 www
Copy the code

At this time. Our defenses are really two layers.

01. Different PHP-FPMs run PHP programs for two virtual hosts, they have their own open_basedir, so it cannot cross directories.

02. Even if open_basedir is bypassed, phP-Fpm running as game01 cannot write or read game02 files because game02 has 750 permissions for all files. Other users do not have any permissions (0).

After everything is set up, say once use method.

0x02 Usage method


/home/start.sh to start the new php-fpm.

/etc/init.d/ PHP -fpm start game01 Start game01 /etc/init.d/ PHP -fpm start game02 Start game02 /etc/init.d/ PHP -fpm stop game01 Start game01 /etc/init.d/php-fpm stop game02 Start game02Copy the code

The above is a little method that I put together, which may not be the best method (I am not familiar with nginx mechanism, maybe there is a simpler way to solve this problem), so I hope that each major can share their own operation and maintenance methods and point out my shortcomings

0 x03 reference:


http://drops.wooyun.org/tips/1323

http://www.dedecms.com/knowledge/servers/linux-bsd/2012/0819/8389.html

http://yzs.me/2198.html