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

dirtysea 发表于 2012-9-17 16:38:07

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

网上关于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.为每个站点建立一个独立用户,都属于同一个组
# groupadd webuser
# useradd   -M   -G webuser-s /sbin/nologin web-a.com

b.建立fastcgi通用启动脚本

# 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通用包含脚本:
# 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.inikey=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:                           

ps aux | grep php-cgi
可以看到脚本已经启动
0.20.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配制
# egrep -v '#.*|^$'/etc/nginx/host/webhost.conf
server {
listen       8888;
#绑定域名
    server_namewww.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 ~* www.b.com/]www.a.com|www.b.com)
    {
         set $sock_file www.a.com-fcgi.sock;
    }
    set $sock_file unix:/tmp/$sock_file;
    location ~ \.php$ {
         include      /etc/nginx/fastcgi_params;
         fastcgi_paramSCRIPT_FILENAME$document_root$fastcgi_script_name;
         fastcgi_paramRoot_Path    $Root_Path;
         fastcgi_paramRoot_HTML    $document_root;
         fastcgi_indexindex.php;
         fastcgi_pass   $sock_file;
   }
}

如果域名与站点设计比较好,可以直接通过读取$host 里面变量,作为fastcgi_pass 参数
注意:
fastcgi_pass 如果不支持变量,需要注意了。这个可能与你的nginx 版本有关系。
测试发现 fastcgi_passnginx 0.639不支持使用变量。后来使用0.7.65版本 支持使用变量了。

dirtysea 发表于 2012-9-17 16:39:34

<H1>Nginx多站点虚拟主机实现单独启动停止php-fpm、单独控制权限设置</H1>
<P>&nbsp;</P>
<P><SPAN style="COLOR: #ff0000"><STRONG>说明:</STRONG></SPAN></P>
<P>站点1:bbs.osyunwei.com 程序所在目录/data/osyunwei/bbs</P>
<P>站点2:sns.osyunwei.com 程序所在目录/data/osyunwei/sns</P>
<P>系统运维 温馨提醒:qihang01原创内容版权所有,转载请注明出处及原文链接</P>
<P><SPAN style="COLOR: #ff0000"><STRONG>相关配置文件目录:</STRONG></SPAN></P>
<P>nginx主配置文件:/usr/local/nginx/conf/nginx.conf</P>
<P>php安装目录:/usr/local/php5/</P>
<P>站点1虚拟主机配置配置文件:/usr/local/nginx/conf/vhost/bbs.conf</P>
<P>站点2虚拟主机配置配置文件:/usr/local/nginx/conf/vhost/sns.conf</P>
<P><SPAN style="COLOR: #ff0000"><STRONG>实现目的:</STRONG></SPAN></P>
<P><SPAN style="COLOR: #0000ff">1、可以对站点1和站点2单独启动、停止php-fpm</SPAN></P>
<P><SPAN style="COLOR: #0000ff">2、站点1和站点2的php运行权限相互隔离,不能跨目录浏览,即站点1内的php木马不能访问站点2中的内容,</SPAN></P>
<P><SPAN style="COLOR: #0000ff">同理,站2内的php木马不能访问站点1中的内容。</SPAN></P>
<P><SPAN style="COLOR: #ff0000"><STRONG>实现方法:</STRONG></SPAN></P>
<P><SPAN style="COLOR: #ff0000">一、为每个站点创建php-fpm.pid文件</SPAN></P>
<P>cd /usr/local/php5/var/run</P>
<P>touch php-fpm-bbs.pid</P>
<P>touch php-fpm-sns.pid</P>
<P><SPAN style="COLOR: #ff0000">二、为每个站点创建php-fpm.conf文件</SPAN></P>
<P>cd /usr/local/php5/etc/</P>
<P>cp php-fpm.conf php-fpm-bbs.conf</P>
<P>cp php-fpm.conf php-fpm-sns.conf</P>
<P><SPAN style="COLOR: #ff0000">三、为每个站点建立php-cgi.sock文件</SPAN></P>
<P>touch /tmp/php-cgi-bbs.sock <SPAN style="COLOR: #0000ff">#建立php-cgi.sock文件</SPAN></P>
<P>chown www.www /tmp/php-cgi-bbs.sock <SPAN style="COLOR: #0000ff">#设置文件所有者为www(必须与nginx的用户一致)</SPAN></P>
<P>touch /tmp/php-cgi-sns.sock</P>
<P>chown www.www /tmp/php-cgi-sns.sock</P>
<P><SPAN style="COLOR: #ff0000">四、编辑相关文件</SPAN></P>
<P><SPAN style="COLOR: #ff0000">vi /usr/local/php5/etc/php-fpm-bbs.conf</SPAN></P>
<P>pid = run/php-fpm-bbs.pid</P>
<P>listen =/tmp/php-cgi-bbs.sock;</P>
<P><SPAN style="COLOR: #ff0000">vi /usr/local/php5/etc/php-fpm-sns.conf</SPAN></P>
<P>pid = run/php-fpm-sns.pid</P>
<P>listen =/tmp/php-cgi-sns.sock;</P>
<P><SPAN style="COLOR: #ff0000">vi /etc/rc.d/init.d/php-fpm</SPAN></P>
<P>vhost=$2</P>
<P>php_fpm_CONF=${prefix}/etc/php-fpm-$vhost.conf</P>
<P>php_fpm_PID=${prefix}/var/run/php-fpm-$vhost.pid</P>
<P>php_opts="-d open_basedir=/data/osyunwei/$vhost/:/tmp/ --fpm-config $php_fpm_CONF"</P>
<P><SPAN style="COLOR: #ff0000">vi /usr/local/nginx/conf/vhost/bbs.conf</SPAN></P>
<P>fastcgi_pass unix:/tmp/php-cgi-bbs.sock;</P>
<P><SPAN style="COLOR: #ff0000">vi /usr/local/nginx/conf/vhost/sns.conf</SPAN></P>
<P>fastcgi_pass unix:/tmp/php-cgi-sns.sock;</P>
<P>cd /home</P>
<P><SPAN style="COLOR: #ff0000">vi start.sh</SPAN> <SPAN style="COLOR: #0000ff">#编辑开机启动脚本</SPAN></P>
<P>#!/bin/bash</P>
<P>auto=$1</P>
<P>/bin/bash /etc/rc.d/init.d/php-fpm $auto bbs</P>
<P>/bin/bash /etc/rc.d/init.d/php-fpm $auto sns</P>
<P>chmod +x start.sh <SPAN style="COLOR: #0000ff">#添加脚本执行权限</SPAN></P>
<P>vi /etc/rc.local <SPAN style="COLOR: #0000ff">#编辑开机启动文件</SPAN></P>
<P>sh /home/start.sh start <SPAN style="COLOR: #0000ff">#加入开机启动</SPAN></P>
<P>service nginx start</P>
<P>/etc/rc.d/init.d/php-fpm start bbs <SPAN style="COLOR: #0000ff">#单独启动站点bbs.osyunwei.com</SPAN></P>
<P>/etc/rc.d/init.d/php-fpm start sns</P>
<P>系统运维 温馨提醒:qihang01原创内容版权所有,转载请注明出处及原文链接</P>
<P>/etc/rc.d/init.d/php-fpm stop bbs <SPAN style="COLOR: #0000ff">#单独停止站点sns.osyunwei.com</SPAN></P>
<P>/etc/rc.d/init.d/php-fpm stop sns</P>
<P><SPAN style="COLOR: #ff0000"><STRONG>五、相关配置文件内容</STRONG></SPAN></P>
<P>/usr/local/nginx/conf/nginx.conf</P><PRE class="brush: php; title: ; notranslate" title="">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;
}
</PRE>
<P>vi /usr/local/nginx/conf/vhost/bbs.conf</P><PRE class="brush: php; title: ; notranslate" title="">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;
}
</PRE>
<P>vi /usr/local/nginx/conf/vhost/sns.conf</P><PRE class="brush: php; title: ; notranslate" title="">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;
}
</PRE>
<P>vi /usr/local/nginx/conf/fcgi.conf</P><PRE class="brush: php; title: ; notranslate" title="">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;
</PRE>
<P>&nbsp;</P>

dirtysea 发表于 2012-9-17 16:40:11

<P>Nginx + PHP5.3中的虚拟主机功能加强</P>
<P>&nbsp;</P>
<DIV class=content>
<P>如果你使用的是Nginx,在一台服务器上使用多个网站,就有可能对服务器的安全感到担心,也会觉得Nginx+php不适合多站点的部署:没有Apache php_admin_value对open_basedir的限制,也没有.htaccess对php.ini的自定义。</P>
<P>PHP5.3及时地对这方面进行弥补,可能很多系统管理员还没有意识,php5.3内置了对nginx这类软件类apache的支持:</P>
<P><STRONG>使用和对php.ini进行自定义</STRONG></P>
<P>举例:</P>
<DIV class=codeText>
<DIV class=codeHead>ASP/Visual Basic代码</DIV>
<OL class=dp-vb>
<LI class=alt><SPAN><SPAN> &nbsp;&nbsp;</SPAN></SPAN>
<LI><SPAN>open_basedir=/var/www/www.pandaidea.com:/tmp &nbsp;&nbsp;</SPAN>
<LI class=alt><SPAN>&nbsp;&nbsp;</SPAN>
<LI><SPAN> &nbsp;&nbsp;</SPAN>
<LI class=alt><SPAN>open_basedir=/var/www/www.tincoco.org:/tmp &nbsp;&nbsp;</SPAN>
<LI><SPAN>&nbsp;&nbsp;</SPAN>
<LI class=alt><SPAN> &nbsp;&nbsp;</SPAN>
<LI><SPAN>open_basedir=/var/www/www.xiayucha.com:/tmp&nbsp;&nbsp;</SPAN> </LI></OL></DIV>
<P>这段配置放在php.ini即可实现主机之间权限的隔离。</P>
<P>Notice:这些设置仅仅在CGI/FastCGI中生效,并且不能设置extension和zend_extension指令。</P>
<P><STRONG>.user.ini的支持</STRONG></P>
<P>根据PHP手册,php在CGI/FastCGI模式中会从当前的PHP脚本目录中开始层层扫描,直到抵达<SPAN class=Apple-style-span style="WORD-SPACING: 0px; FONT: italic 14px verdana, arial, helvetica, sans-serif; TEXT-TRANSFORM: none; COLOR: rgb(0,0,0); TEXT-INDENT: 0px; WHITE-SPACE: normal; LETTER-SPACING: normal; BACKGROUND-COLOR: rgb(255,255,255); webkit-text-size-adjust: auto; widows: 2; orphans: 2; webkit-text-decorations-in-effect: none; webkit-text-stroke-width: 0px">$_SERVER['DOCUMENT_ROOT']</SPAN>。除非当前脚本是在DOCUMENT_ROOT之外执行,只会扫描当前目录。</P>
<P>读取.user.ini后会缓存起来,根据<SPAN class=Apple-style-span style="WORD-SPACING: 0px; FONT: 14px verdana, arial, helvetica, sans-serif; TEXT-TRANSFORM: none; COLOR: rgb(0,0,0); TEXT-INDENT: 0px; WHITE-SPACE: normal; LETTER-SPACING: normal; BACKGROUND-COLOR: rgb(255,255,255); webkit-text-size-adjust: auto; widows: 2; orphans: 2; webkit-text-decorations-in-effect: none; webkit-text-stroke-width: 0px"><EM>user_ini.cache_ttl</EM></SPAN>确定重新读取的时间,默认是5分钟。</P>
<P>不过<EM>PHP_INI_SYSTEM</EM> 级别的不能在.user.ini中设置。</P>
<P>有这两个功能的支持,nginx + php-fpm的安全程度以及功能已经和Apache类似。也看到一些公司开始推出一些nginx虚拟主机,毕竟,Nginx虚拟主机更容易超售;服务器/VPS上放多个站点也不用担心某个使用开源程序的站点成了害群马。</P></DIV>
页: [1]
查看完整版本: Nginx + PHP虚拟主机的权限限制