服务器维护,服务器代维,安全设置,漏洞扫描,入侵检测服务

运维之家

 找回密码
 注册
搜索
查看: 8165|回复: 2

Nginx + PHP虚拟主机的权限限制

[复制链接]
dirtysea 发表于 2012-9-17 16:38:07 | 显示全部楼层 |阅读模式
网上关于nginx +fastcgi+php 虚拟主机独立站点安全配置文章很多。
其中 关于Nginx+PHP的虚拟主机目录权限控制的探究   文章已经讲的很详细了。方法很多,有设置http://www.cnblogs.com/http://www.cnblogs.com/ 特殊目录的,有通过open_basedir配制独立站点,独立目录的。 还有将所有站点目录都写在open_basedir里面。只是没有站点用比较特殊目录名称。别人不知道目录的。是进去不了。还有修改php 源码,加入root_path限制,访问目录。

那么我写这篇文章,不想再去考虑怎么样限制在某个目录了。 我主要要说的是:、
1,php.ini 安全配置
2,通过启动多个php-cgi怎么样实现灵活配制
3,nginx fastcgi_pass 怎么样控制发到不同的fastcgi

如果你对这些都比较清楚,可以忽略跳过下面的了。

1.php.ini 安全配置
配制项目
说明

allow_url_fopen=Off
allow_url_include=Off
禁止远程包含

register_globals=Off
禁止自动注册全局变量

open_basedir="\tmp:"
限制操作文件路径(具体站点具体路径)

safe_mode=Off
safe_mode_gid=Off
禁止使用安全模式

max_execution_time=30
max_input_time=60
限制脚本执行时间(避免耗时限制语句)

memory_limit=32M
upload_max_filesize=5M
post_max_size=8M
max_input_nesting_levels=64
限制内存,及文件尺寸

display_errors=Off
log_errors=On
error_log="/var/log/nginx/phperror.log"
安全的错误配制

fastcgi.logging=0
cgi.fix_pathinfo=0
禁止fastcgi 的pathinfo
最近nginx漏洞在此

expose_php=Off
隐藏php的版本信息

enable_dl=Off
关闭dl参数

disable_functions =phpinfo,exec,passthru,shell_exec,system,proc_open,
popen,curl_exec,curl_multi_exec,parse_ini_file,show_source
禁止恶意函数执行

以上我都不打算多说了。参数意思可以看看php手册。

2.fastcgi  启动脚本
a.为每个站点建立一个独立用户,都属于同一个组
[root@localhost ~]# groupadd webuser
[root@localhost ~]# useradd   -M   -G webuser  -s /sbin/nologin web-a.com

b.建立fastcgi通用启动脚本

[root@www]# egrep -v '#.*|^$' php-cgi.sh
. /etc/rc.d/init.d/functions   
SPAWNFCGI="/usr/local/bin/spawn-fcgi"  
FCGIPROGRAM="/usr/bin/php-cgi"  
FCGIPROGRAM2="$FCGIPROGRAM $CGI_OPTIONS"  
PHP_FCGI_MAX_REQUESTS=500  
FCGI_WEB_SERVER_ADDRS="127.0.0.1"  
ALLOWED_ENV="SHELL PATH USER"  
if test x$PHP_FCGI_CHILDREN = x; then   
PHP_FCGI_CHILDREN=5  
fi   
prog="${tmpfile%.*}-fcgi"
FCGI_SOCKET="/tmp/$prog.sock"
FCGI_PIDFILE="/var/run/$prog.pid"
FCGI_LOCKFILE="/var/lock/subsys/$prog"
export PHP_FCGI_MAX_REQUESTS   
export FCGI_WEB_SERVER_ADDRS   
ALLOWED_ENV="$ALLOWED_ENV PHP_FCGI_MAX_REQUESTS FCGI_WEB_SERVER_ADDRS"  
if test x$UID = x0; then   
EX="$SPAWNFCGI -s $FCGI_SOCKET -f \"$FCGIPROGRAM2\" -u $USERID -g $GROUPID -C $PHP_FCGI_CHILDREN -P $FCGI_PIDFILE"  
else   
EX="$SPAWNFCGI -s $FCGI_SOCKET -f \"$FCGIPROGRAM2\" -C $PHP_FCGI_CHILDREN -P $FCGI_PIDFILE"  
fi   
E=   
for i in $ALLOWED_ENV; do   
E="$E $i=${!i}"  
done   
RETVAL=0  
status() {
local pid
        echo $"Usage: status {program}"
        return 1
fi
pid=`pgrep $base -u $USERID | sed 's/\n/\t/g'`
if [ -n "$pid" ]; then
        echo $"${prog} (pid $pid) is running..."
        return 0
fi
if [ -f $FCGI_PIDFILE ] ; then
        read pid < $FCGI_PIDFILE
        if [ -n "$pid" ]; then
                echo $"${prog} dead but pid file exists"
                return 1
        fi
fi
if [ -f $FCGI_LOCKFILE ]; then
        echo $"${prog} dead but subsys locked"
        return 2
fi
echo $"${prog} is stopped"
return 3
}
start() {   
        echo -n $"Starting $prog: "   
        daemon env - $E $EX   
chmod 777 $ FCGI_SOCKET
        RETVAL=$?   
        echo   
        [ $RETVAL -eq 0 ] && touch $FCGI_LOCKFILE   
        return $RETVAL   
}   
stop() {   
        echo -n $"Stopping $prog: "   
                rm -f $FCGI_PIDFILE $FCGI_SOCKET   
                RETVAL=$?   
                [ "$RETVAL" -eq 0 ] && success "startup" || failure "startup"
                echo   
                [ $RETVAL -eq 0 ] && rm -f $FCGI_LOCKFILE   
                return $RETVAL   
}   
case "$1" in   
start)   
start   
;;   
stop)   
stop   
;;   
restart)   
stop   
start   
;;   
condrestart)   
if [ -f $FCGI_LOCKFILE ]; then   
stop   
start   
fi   
;;   
status)   
status $FCGIPROGRAM   
RETVAL=$?   
;;   
*)   
echo $"Usage: $0 {start|stop|restart|condrestart|status}"   
RETVAL=1  
esac   
exit $RETVAL

上面这个脚本是我用网上脚本改造而成,主要修改,当重启,或者stop 莫个站点php-cgi 实际是将所有站点都停止了。 这样不符合独立虚拟主机的独立管理原则。

c.独立站点的 启动脚本
web-chaohao.com通用包含脚本:
[root@www]# egrep -v '#.*|^$' www.a.com.sh
export PATH=/usr/bin:/bin:/usr/local/bin:/usr/X11R6/bin;
export LANG=zh_CN.GB2312;
#启动php-cgi 线程数量
PHP_FCGI_CHILDREN=30;
#启动账户
USERID= web-a.com;
#启动群组
GROUPID=webuser;
CGI_OPTIONS=" -d open_basedir=/home/www/a/:/tmp/ -C  ";
TMPPATH=`dirname $0`;
. $TMPPATH/php-cgi.sh;

从上面脚本应该可以看出,这个是每个站点一个脚本,然后脚本,包含 通用脚本 php-cgi.sh
www.a.com.sh  这个里面有个CGI_OPTIONS 配制选项,可以控制open_basedir 允许的站点。 当然,也可以配置其它php.ini  key=value 参数。
值得注意的是:
i. 多个配制的话,可以用多个-d 参数。  -d open_basedir=/tmp -d display_errors=on  这样就会覆盖掉php.ini 里面配置。 呵呵,比较简单吧。
ii.很奇怪是当 php -v 版本是:5.1.6好像不起作用,后来升级到5.2.6 配制就生效了。 php-cgi -d 后面设置不生效的情况下,请看下你的php版本。
iii.php-cgi.sh 与站点脚本www.a.com.sh 放到同一目录.

d.启动站点
chmod +x www.a.com.sh
./www.a.com.sh
Usage: ./www.chaohao.com.sh {start|stop|restart|condrestart|status}
可以带参数。
./www.a.com.sh start
Starting www.a.com-fcgi:                             [  OK  ]

ps aux | grep php-cgi
可以看到脚本已经启动
0.2  0.1 82040 7692 ?        Ss   16:35   0:00 /usr/bin/php-cgi -d open_basedir=/home/www/html/www.a.com/:/tmp/ -C
................

e.脚本解析
上面脚本,会自动创建
/var/run/脚本文件名-fcgi.pid
/tmp/脚本文件名-fcgi.sock
文件。 如果执行脚本是,www.a.com.sh
创建文件对应是:/var/run/www.a.com-fcgi.pid 以及 /tmp/www.a.com-fcgi.sock

建议站点名称,最好能够跟用户名,以及脚本名称统一。如果你的站点是 www.b.com
useradd 设置为 web-b.com
shell脚本设置为b.com.sh

3.nginx sever配制
[root@web49 nginx]# egrep -v '#.*|^$'  /etc/nginx/host/webhost.conf
server {
listen       8888;
#绑定域名
    server_name  www.a.com www.b.com;  
    access_log   /var/log/nginx/chaohao.access.log main;
    error_log    /var/log/nginx/chaohao.error.log;
    index index.php index.shtml;
    set $test_host www.chaohao.com;
    set     $Root_Path /home/www/html/$test_host;
    root    $Root_Path/html;
    set $sock_file www.chaohao.com-fcgi.sock;
    if ($host ~* [url=http://www.a.com|www.b.com/]www.a.com|www.b.com[/url])
    {
         set $sock_file www.a.com-fcgi.sock;
    }
    set $sock_file unix:/tmp/$sock_file;
    location ~ \.php$ {
           include        /etc/nginx/fastcgi_params;
           fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
           fastcgi_param  Root_Path    $Root_Path;
           fastcgi_param  Root_HTML    $document_root;
           fastcgi_index  index.php;
           fastcgi_pass   $sock_file;
     }
}

如果域名与站点设计比较好,可以直接通过读取$host 里面变量,作为fastcgi_pass 参数
注意:
fastcgi_pass 如果不支持变量,需要注意了。这个可能与你的nginx 版本有关系。
测试发现 fastcgi_pass  nginx 0.639不支持使用变量。后来使用0.7.65版本 支持使用变量了。
 楼主| dirtysea 发表于 2012-9-17 16:39:34 | 显示全部楼层

Nginx多站点虚拟主机实现单独启动停止php-fpm、单独控制权限设置

 

说明:

站点1:bbs.osyunwei.com 程序所在目录/data/osyunwei/bbs

站点2:sns.osyunwei.com 程序所在目录/data/osyunwei/sns

系统运维 温馨提醒:qihang01原创内容版权所有,转载请注明出处及原文链接

相关配置文件目录:

nginx主配置文件:/usr/local/nginx/conf/nginx.conf

php安装目录:/usr/local/php5/

站点1虚拟主机配置配置文件:/usr/local/nginx/conf/vhost/bbs.conf

站点2虚拟主机配置配置文件:/usr/local/nginx/conf/vhost/sns.conf

实现目的:

1、可以对站点1和站点2单独启动、停止php-fpm

2、站点1和站点2的php运行权限相互隔离,不能跨目录浏览,即站点1内的php木马不能访问站点2中的内容,

同理,站2内的php木马不能访问站点1中的内容。

实现方法:

一、为每个站点创建php-fpm.pid文件

cd /usr/local/php5/var/run

touch php-fpm-bbs.pid

touch php-fpm-sns.pid

二、为每个站点创建php-fpm.conf文件

cd /usr/local/php5/etc/

cp php-fpm.conf php-fpm-bbs.conf

cp php-fpm.conf php-fpm-sns.conf

三、为每个站点建立php-cgi.sock文件

touch /tmp/php-cgi-bbs.sock #建立php-cgi.sock文件

chown www.www /tmp/php-cgi-bbs.sock #设置文件所有者为www(必须与nginx的用户一致)

touch /tmp/php-cgi-sns.sock

chown www.www /tmp/php-cgi-sns.sock

四、编辑相关文件

vi /usr/local/php5/etc/php-fpm-bbs.conf

pid = run/php-fpm-bbs.pid

listen =/tmp/php-cgi-bbs.sock;

vi /usr/local/php5/etc/php-fpm-sns.conf

pid = run/php-fpm-sns.pid

listen =/tmp/php-cgi-sns.sock;

vi /etc/rc.d/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=/data/osyunwei/$vhost/:/tmp/ --fpm-config $php_fpm_CONF"

vi /usr/local/nginx/conf/vhost/bbs.conf

fastcgi_pass unix:/tmp/php-cgi-bbs.sock;

vi /usr/local/nginx/conf/vhost/sns.conf

fastcgi_pass unix:/tmp/php-cgi-sns.sock;

cd /home

vi start.sh #编辑开机启动脚本

#!/bin/bash

auto=$1

/bin/bash /etc/rc.d/init.d/php-fpm $auto bbs

/bin/bash /etc/rc.d/init.d/php-fpm $auto sns

chmod +x start.sh #添加脚本执行权限

vi /etc/rc.local #编辑开机启动文件

sh /home/start.sh start #加入开机启动

service nginx start

/etc/rc.d/init.d/php-fpm start bbs #单独启动站点bbs.osyunwei.com

/etc/rc.d/init.d/php-fpm start sns

系统运维 温馨提醒:qihang01原创内容版权所有,转载请注明出处及原文链接

/etc/rc.d/init.d/php-fpm stop bbs #单独停止站点sns.osyunwei.com

/etc/rc.d/init.d/php-fpm stop sns

五、相关配置文件内容

/usr/local/nginx/conf/nginx.conf

user www www;
worker_processes 2;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;

events {
 use epoll;
 worker_connections 65535;
}

http {
 include mime.types;
 default_type application/octet-stream;

 #log_format main '$remote_addr - $remote_user [$time_local] "$request" '
 # '$status $body_bytes_sent "$http_referer" '
 # '"$http_user_agent" "$http_x_forwarded_for"';

 #access_log logs/access.log main;
 server_names_hash_bucket_size 128;
 client_header_buffer_size 32k;
 large_client_header_buffers 4 32k;
 client_max_body_size 300m;
 sendfile on;
 tcp_nopush on;
 fastcgi_connect_timeout 300;
 fastcgi_send_timeout 300;
 fastcgi_read_timeout 300;
 fastcgi_buffer_size 64k;
 fastcgi_buffers 4 64k;
 fastcgi_busy_buffers_size 128k;
 fastcgi_temp_file_write_size 128k;
 #keepalive_timeout 0;
 keepalive_timeout 60;
 tcp_nodelay on;
 server_tokens off;
 gzip on;
 gzip_min_length 1k;
 gzip_buffers 4 16k;
 gzip_http_version 1.1;
 gzip_comp_level 2;
 gzip_types text/plain application/x-javascript text/css application/xml;
 gzip_vary on;
 server
 {
 listen 80 default;
 server_name _;
 location / {
 root html;
 return 404;
 }
 location ~ /.ht {
 deny all;
 }
 }
 server
 {
 listen 80;
 #server_name localhost;
 index index.php default.php index.html index.htm default.html default.htm ;

 location /status {
 stub_status on;
 access_log off;
 }

 location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$
 {
 expires 30d;
 }
 location ~ .*\.(js|css)?$
 {
 expires 12h;
 }

 access_log off;
 }

include vhost/*.conf;
}

vi /usr/local/nginx/conf/vhost/bbs.conf

server
 {
 listen 80;
 server_name bbs.osyunwei.com;
 index index.php index.html index.htm default.html default.htm default.php;
 root /data/osyunwei/bbs;
location ~ .*\.(php|php5)?$
 {
 fastcgi_pass unix:/tmp/php-cgi-bbs.sock;
 fastcgi_index index.php;
 include fcgi.conf;
 }
 location /status {
 stub_status on;
 access_log off;
 }

 location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$
 {
 expires 30d;
 }
 location ~ .*\.(js|css)?$
 {
 expires 12h;
 }

 access_log off;
 }

vi /usr/local/nginx/conf/vhost/sns.conf

server
 {
 listen 80;
 server_name sns.osyunwei.com;
 index index.php index.html index.htm default.html default.htm default.php;
 root /data/osyunwei/sns;
location ~ .*\.(php|php5)?$
 {
 fastcgi_pass unix:/tmp/php-cgi-sns.sock;
 fastcgi_index index.php;
 include fcgi.conf;
 }
 location /status {
 stub_status on;
 access_log off;
 }

 location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$
 {
 expires 30d;
 }
 location ~ .*\.(js|css)?$
 {
 expires 12h;
 }

 access_log off;
 }

vi /usr/local/nginx/conf/fcgi.conf

fastcgi_param GATEWAY_INTERFACE CGI/1.1;
fastcgi_param SERVER_SOFTWARE nginx/$nginx_version;

fastcgi_param QUERY_STRING $query_string;
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param CONTENT_TYPE $content_type;
fastcgi_param CONTENT_LENGTH $content_length;

fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_param REQUEST_URI $request_uri;
fastcgi_param DOCUMENT_URI $document_uri;
fastcgi_param DOCUMENT_ROOT $document_root;
fastcgi_param SERVER_PROTOCOL $server_protocol;

fastcgi_param REMOTE_ADDR $remote_addr;
fastcgi_param REMOTE_PORT $remote_port;
fastcgi_param SERVER_ADDR $server_addr;
fastcgi_param SERVER_PORT $server_port;
fastcgi_param SERVER_NAME $server_name;

# PHP only, required if PHP was built with --enable-force-cgi-redirect
fastcgi_param REDIRECT_STATUS 200;

 

 楼主| dirtysea 发表于 2012-9-17 16:40:11 | 显示全部楼层

Nginx + PHP5.3中的虚拟主机功能加强

 

如果你使用的是Nginx,在一台服务器上使用多个网站,就有可能对服务器的安全感到担心,也会觉得Nginx+php不适合多站点的部署:没有Apache php_admin_value对open_basedir的限制,也没有.htaccess对php.ini的自定义。

PHP5.3及时地对这方面进行弥补,可能很多系统管理员还没有意识,php5.3内置了对nginx这类软件类apache的支持:

使用[PATH]和[HOST]对php.ini进行自定义

举例:

ASP/Visual Basic代码
  1. [HOST=www.pandaidea.com]   
  2. open_basedir=/var/www/www.pandaidea.com:/tmp   
  3.   
  4. [PATH=/var/www/www.tincoco.org]   
  5. open_basedir=/var/www/www.tincoco.org:/tmp   
  6.   
  7. [PATH=/var/www/www.xiayucha.com]   
  8. open_basedir=/var/www/www.xiayucha.com:/tmp  

这段配置放在php.ini即可实现主机之间权限的隔离。

Notice:这些设置仅仅在CGI/FastCGI中生效,并且不能设置extension和zend_extension指令。

.user.ini的支持

根据PHP手册,php在CGI/FastCGI模式中会从当前的PHP脚本目录中开始层层扫描,直到抵达$_SERVER['DOCUMENT_ROOT']。除非当前脚本是在DOCUMENT_ROOT之外执行,只会扫描当前目录。

读取.user.ini后会缓存起来,根据user_ini.cache_ttl确定重新读取的时间,默认是5分钟。

不过PHP_INI_SYSTEM 级别的不能在.user.ini中设置。

有这两个功能的支持,nginx + php-fpm的安全程度以及功能已经和Apache类似。也看到一些公司开始推出一些nginx虚拟主机,毕竟,Nginx虚拟主机更容易超售;服务器/VPS上放多个站点也不用担心某个使用开源程序的站点成了害群马。

您需要登录后才可以回帖 登录 | 注册

本版积分规则

QQ|小黑屋|手机版|Archiver|运维之家

GMT+8, 2024-3-29 23:54 , Processed in 0.087353 second(s), 17 queries .

Powered by Dirtysea

© 2008-2020 Dirtysea.com.

快速回复 返回顶部 返回列表