共享主机配置php open_basedir提高安全 防止文件被跨站访问


关于nginx/php-fpm/apache mod_php中的安全配置,可参考我以前的另一个文章:php

《正确设置nginx/php-fpm/apache 提升网站安全性 防止被挂木马》linux

http://zhangxugg-163-com.iteye.com/blog/1171572nginx


1、基础知识准备shell

在任何配置开始前,必定要搞清楚这几个概念,若是这几个概念没有完全弄清楚,就没法理解后续的配置的意义了, 有经验的系统管理员可跳过。apache

1. 站点文件全部者帐户是什么,文件的权限又是什么?windows

2.nginx, php-fpm, apache用什么帐户运行?缓存

3.网站的哪些目录和文件是可写的?这里的可写,是指对于nginx ? php-fpm ? 仍是apache ?安全

4.如何禁止php代码被执行?框架


Linux的最基本的权限是:文件的全部者,对其所属全部文件都有任何权限(root权限不受限制),读写执行权限分别被标识为4 2 1yii

我看到最多的是,一些系统管理员为了省事,让php-fpm/apache以网站文件全部者,这样方便php程序在任何位置生成文件, 但这样配置却可能形成严重的安全问题。


上面几个问题的回复:

1.在linux目录中,使用ls -l命令便可查看当前目录全部者,第三、4列分别文件所属于的用户/组,如图示,这是yii框架的protected目录中的文件列表

咱们能够看到,文件全部者和组是ftp, runtime目录权限是任何人有读写执行权限.

2.站点中,每每须要可写目录,用于运行时生成文件(缓存、静态文件、附件上传等),因此这个可写,是针对php程序自己而言的,nginx+php-fpm模式下,nginx只是负责把请求转发给php-fpm进程,因此最终的生成文件是由php-fpm产生的。可是Apache mod_php却有所不一样,mod_php做为apache的一个模块,其权限继承自apache, 故说成apache的可写目录,也不为错。


能够用命令  ps aux | egrep 'nginx|php-fpm|apache'  查看nginx/php-fpm/apache运行帐户


3.与开发人员沟通,了解可写目录及其意义


4.若是禁止php代码被执行?可能因为程序代码漏洞,木马文件被上传到了附件目录,你可能认为在linux中去掉这个目录的执行权限就好了?

chmod a-x  -R uploadfile

但这样就致使apache没法读取此目录的文件,致使附件文件没法被访问了。另外一方面,这种方式也是错误的。即使是去掉附件文件自己的执行权限(普通文件自己,是没有执行权限),也是行不通的,要先了解php的运行机制。


php的经常使用运行方式有如下几种:

A . 以nginx+php-fpm的方式运行

B. 以apache mod_php方式运行

C. 命令行下,使用php  <filename.php> 方式运行

D. 在php脚本第一行添加:#!/usr/local/php/bin/php, 并给此文件添加执行权限,就能够把它当成一shell脚本运行了。这种文件并不常见。


这几种方式中,只有最后一种方式才须要执行权限,其它几种方式下,只要php解释器进程对php脚本有读取权限,便可运行。关于如何禁止php脚本的执行,可参阅做者的上述文章。


2、safe_mode

php的安全模式备受争议,由于它涉及系统配置,并且它是使用了windows的配置思想,在Linux环境中并不适合。简单地说,开启safe_mode后,php进程自己只容许打开属于它本身的脚本文件。也就是说,在多站点环境中,咱们必须为每一个站点创建一个用户,并让php进程以对应的帐户权限运行, 这样它能够对本身的站点文件有最高权限,但对其它用户的文件,则没有任何权限。听起来不错,但事实上这个配置起来的工做量至关繁琐并且极容易出错:

1. 若是站点不少,须要创建大量帐户,须要将站点目录分别受权给这些用户

2.php-fpm须要创建大量的进程池,并指定不一样的帐户身份, 可能形成fpm进程资源浪费

3.apachce不能配置多个运行帐户,只能指定一个。

4.共享目录(如/tmp, /dev/shm等须要单独指定),并非一件容易的事。

可见,正由于safe_mode配置如此繁琐, php新版将取消safe_mode的支持,PHP手册上已经描述很清楚:

5. 若是站点要迁移到其它机器,用户帐户也须要彻底迁移,这也是很繁琐的工做量。


安全模式自 PHP 5.3.0 起废弃并将自 PHP 5.4.0 起移除。


因此,依赖安全模式的方式,在php新版本中将不会被支持,笔者编写这个文章时,php 7.0.2已经发布。


3、为何要用open_basedir

open_basedir 用于限制php进程能够打开的目录前缀,通常来讲,php程序除了须要读取本站点的文件外,还每每会用到/tmp /dev/shm目录。

假设站点位于 /data/wwwroot/site.cn,在运行时要用到/tmp, /dev/shm, /proc目录,那么能够在php.ini中这样设置

open_basedir = /data/wwwroot/site.cn:/tmp:/dev/shm:/proc

若是php中使用include, require, fopen, gzopen等函数加载其它目录文件,就会报错:

require_once(): open_basedir restriction in effect. File(file.php) is not within the allowed path(s): (PATH) 

Warning: require_once(file.php): failed to open stream: Operation not permitted in 

Fatal error: require_once(): Failed opening required ...


这个参数在 php 5.2.3时只能在php.ini中配置,没法在运行时配置。php 5.2.3时,能够在任何位置设置。


显然,针对一个有大量站点的主机, 使用多个php.ini的方式,就很是难以配置。方法有两种:

1.在php-fpm.conf配置文件中,为每一个进程池指定不一样的限定目录

[www]

php_admin_value[open_basedir] = /var/www/www.example.com:/usr/share/php5:/tmp:/usr/share/phpmyadmin:/etc/phpmyadmin

php_admin_value是指此值一旦设置,没法在运行时被修改。但这种方法,却并不被推荐的,由于每一个站点都须要创建一个进程池,有100个站点,就须要创建100个进程池,并且这些php进程,没法互相使用,只能是站点独享,形成资源极大浪费。


2.nginx经过fastcgi协议和php-fpm通讯时,能够指定一些参数,用于在请求开始前,修改php的配置参数, 这是最为方便有效的方法,强制推荐


fastcgi_param PHP_ADMIN_VALUE "open_basedir=$document_root/:/tmp/:/proc/:/dev/shm";

这是php-fpm特有的功能,表示从fastcgi客户端能够接收一些参数指定

因为$document_root变量的引入,咱们就能够直接批量配置了。

这样一来,全部站点可共享同一个进程池,同时又解决了分别限制访问目录的问题。咱们能够把这个指令加入到nginx的fastcgi_params配置文件中,这样全部站点就当即生效,解决了难题

能够用如下php代码测试一下

<?php


echo ini_get('open_basedir');

ini_set('open_basedir', '/etc/');

echo ini_get('open_basedir');


可见已经设置为所指望的限制,并没有法在运行时进行修改的。 经过这个触类旁通,咱们能够在nginx根据须要指定php的各类配置了

相关文章
相关标签/搜索