欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  php教程

PHP-FPM之Chroot执行环境详解

程序员文章站 2022-05-08 11:16:57
...

在PHP-FPM中设立chroot,有很好的隔离作用,提高系统安全性,但是要想建立一个合理的PHP-FPM Chroot环境难度有点大,比用debootstrap等工具建立还要麻烦,这篇文

在PHP-FPM中设立chroot,有很好的隔离作用,提高系统安全性,但是要想建立一个合理的PHP-FPM Chroot环境难度有点大,比用debootstrap等工具建立还要麻烦,下面通过参考相关资料,把PHP-FPM之Chroot执行环境整理出来,分享给大家。

本文以Ubuntu 14.04.2为例,php-fpm使用的是 ppa:ondrej/php5-5.6 提供的PHP5.6版本,跟系统自带以及Debian系统的php-fpm和系统目录结构应该是一致的。CentOS请自行调整。

php-fpm的chroot环境配置和所使用的服务器前端没有关联,也不强求Apache/Nginx进行chroot。当然那样更安全——也更复杂。

1.建立目录结构

chroot的目录选择为 /var/www/chroot ,其中页面文件放置在 /var/www/chroot/public 。

执行下面的命令建立基本的目录结构:

bash mkdir -p /var/www/chroot/ cd /var/www/chroot mkdir -p public bin dev tmp usr/sbin/ usr/share/zoneinfo/ var/run/nscd/ var/lib/php5/sessions var/www cp -a /dev/zero /dev/urandom /dev/null dev/ #注3 chmod --reference=/tmp tmp/ chmod --reference=/var/lib/php5/sessions var/lib/php5/sessions #注4 chown -R root:root . #注2 chown -R www-data:www-data public/ #注2 cd var/www ln -s ../.. chroot #注1

下面是此时目录结构,之后还会添加一些新的东西:

/var/www/chroot/ ├── bin ├── dev │ ├── null │ ├── urandom │ └── zero ├── public ├── tmp ├── usr │ ├── sbin │ └── share │ └── zoneinfo └── var ├── lib │ └── php5 │ └── sessions ├── run │ └── nscd └── www └── chroot -> ../.. #注1

注1:这个软连接用于解决Apache/nginx传给php-fpm的 SCRIPT_FILENAME 在进入chroot后找不到文件(访问php页面返回"File not found")的问题。

以nginx为例,通常设置 SCRIPT_FILENAME 为 $document_root$fastcgi_script_name ,传给php-fpm的脚本路径就是 /var/www/chroot/public/index.php 。而由于php-fpm处在chroot环境下,所以它实际试图去访问的路径就变成了 /var/www/chroot + /var/www/chroot/public/index.php 当然是不存在的。

所以使用一个软连接把chroot环境下的 /var/www/chroot 链接到根目录,就能够正常访问脚本了。

当然也可以将 SCRIPT_FILENAME 设置成 /public$fastcgi_script_name 。但是这样硬编码不利于配置的迁移,仅能用于chroot的环境,切换回非chroot环境的话还需要修改配置。所以不建议这么做。(顺便说一句,有很多老教程里也不使用 $document_root ,直接硬编码根目录,当然也是不可取的)

注2:chroot环境并不是100%安全的。由于php-fpm在chroot环境中的执行权限是www-data,仍然建议把非必要的目录的拥有者设置为root来减少不必要的访问权限。chroot不等于安全,参考 chroot最佳实践 中列出的一些原则。从更安全的角度上讲之后最好也将bin、lib、sbin等目录的读写权限去掉,只留可执行权限,不过也没大差别了……

注3:cp -a除了拷贝文件内容外也会复制文件的权限、模式等信息,可以很方便的直接拿来拷贝zero、urandom和null这三个关键的设备文件。mknod似乎是更为稳妥的方式,不过cp -a我使用起来似乎也没问题。

注4:chmod --reference=XXX会参考XXX的权限设置后面的权限。tmp就不提了,关键是后面的 var/lib/php5/sessions 是php存放session文件的目录,需要让www-data有读写的权限。建议设置完之后再看一眼。当然后面会有测试。

2.PHP-FPM的配置

建立一个新的php-fpm的执行pool来搭建chroot环境。并不建议直接修改php-fpm.conf,因为这样是全局生效的,如果有多个php站点的话会共用一套chroot环境。

其实很多php-fpm的教程都忽略了php-fpm的pool的配置,导致很多人一台服务器上所有站点都共用一套配置,尤其是共用一套php.ini的配置,实际上是不合理的。应当根据站点的需求单独建立pool并在其中调整参数。

在 /etc/php5/fpm/pool.d/ 下新建 chroot.conf (注意必须以.conf结尾,才能被php-fpm.conf调用):

[chroot] user = www-data group = www-data listen = /var/run/php-chroot.sock listen.owner = www-data listen.group = www-data pm = dynamic pm.max_children = 5 pm.start_servers = 1 pm.min_spare_servers = 1 pm.max_spare_servers = 3 chroot = /var/www/chroot chdir = /public ;security.limit_extensions = .php php_flag[display_errors] = on php_value[date.timezone] = Asia/Hong_Kong ;php_admin_value[session.gc_probability] = 1 ;php_admin_value[open_basedir] = "/tmp/:/public/:/var/www/chroot/public/"

前面的参数都比较熟悉了。只需要简单的设置chroot为配置好的环境根目录就可以开启chroot了。通过执行 php5-fpm -t 测试一下之后,用 service php5-fpm reload 即可启用新的pool。当然Apache/nginx对应的配置中要设置好后端。

提一下最后几行。倒数第四行打开了 display_errors ,以便之后对chroot下的php的功能进行测试,测试完了记得注释掉。

设置 session.gc_probability 允许php进程自行对session进行删除回收。正常情况下session是由php添加的cron任务清理的,但是似乎php不会自动清理chroot环境下的session。当然也可以自己在cron.d下添加自动执行的脚本来清理,就不用开启这个选项了。

3.修复Chroot环境下PHP的各项功能

在/var/www/chroot/public下新建一个test.php,写入以下内容:

复制代码 代码如下:


php
session_start();
header( "Content-Type: text/plain" );
echo( gethostbyname( "localhost" )."\n" );
print_r( getdate() );
mail( "your@address", "subject", "message" );

这里主要测试的功能是:session、DNS解析、时间和日期、邮件mail()函数。

访问上面的测试页面,提示No such directory or file或者Permission denied说明session配置不正确。 gethostbyname 返回的不是127.0.0.1或者::1,则说明DNS解析没有生效。提示 timezone database is corrupt 之类的,说明时间和日期有错误。mail()也会有各种错误提示。

session就不提了,设置好目录权限就没有问题。主要处理一下后面三个问题,也是php的chroot环境主要需要处理的内容。

3.1 域名解析/时区等问题

mail()的解决方法大同小异,放后面谈。前面的域名解析等问题这里我介绍两种解决方法。方法1是参考Kienzl的简便方法,方法2是大部分教程采用的方法。

方法1:使用nscd