正确设置 php-fpm子进程用户 提高网站安全性 防止被挂木马

核心总结:php-fpm 子进程所使用的用户,不能是网站文件所有者。 凡是违背这个原则,则不符合最小权限原则。

根据生产环境不断反馈,发现不断有 php网站被挂木马,绝大部分原因是因为权限设置不合理造成。因为服务器软件,或是 php 程序中存在漏洞都是难免的,在这种情况下,如果能正确设置 Linux 网站目录权限, php 进程权限,那么网站的安全性实际上是可以得到保障的。

那么,造成网站被挂木马的原因是什么?

1.  ftp 连接信息被破解,对这个原因,可行的办法就是使用非常复杂的FTP 用户名(不要使用常用的用户名),如果是固定作业,可考虑使用 iptables 防火墙限制来源 IP 。但是一些情景下,可能需要使用 VPN 以便远程维护。 即网站维护者需要使用 FTP 修改网站文件时,必须先登录到 IDC 机房的 VPN 服务器上,再进行后续的操作。

2.  网站服务器软件/ 配置 /php 程序存在漏洞,被利用
在讨论这个问题前,先说明文件及进程权限的几个概念:
A. FTP用户对网站目录具有最大修改权限,那么网站的文件所有者一定属于 FTP,  这是毋庸置疑的 , 否则如何修改文件呢?
B. php-fpm进程, nginx 进程对网站文件至少需要有读取权限,例如,以下命令即可查看这两个进程所使用的账号:


通过上图,我们可以发现,nginx 和 php-fpm 子进程账号是 nobody 。

我们再查看网站文件目录的权限:

发现网站文件所有者是www 账号,那说明:
| nginx和 php 对网站只有读取权限,无写入权限
l 如果php 程序需要对网站某些文件有写入权限,需要手工将文件或目录权限修改为 777
l 因为php-fpm 子进程是以 nobody 运行,那么 php-fpm 生成的新文件所有者也是 nobody, 这时 ftp 用户将无法修改这些文件,解铃还需系铃人,当 php 生成文件后,需要调用 chmod(“/somedir/somefile”, 0777) 将文件权限修改为 777 ,以便 FTP 用户也可以修改这个文件。
l 经常有开发人员找我请求重设php 生成的文件的权限。

l 如果php-fpm 子进程以网站文件所有者用户运行,那意味着 php-fpm 进程对整个网站目录具有可写权限,噩梦也就由此开始。

但是我们发现,有不少系统管理员为了省事,违背了Linux 最小化权限的原则,设置 php-fpm 进程以网站文件所有者账号运行,当然这样可能会方便 php 开发人员( php-fpm 进程对整个网站目录具有可写权限),但是这样一来, Linux 体系的文件系统权限原则将被打破,所有的安全措施将形同虚设。可以想象的是,万一 php 程序中有漏洞,攻击者上传木马,便可以修改网站的所有文件,网站首页被黑,也就不足为怪了。

退一步,如果我们设置了较严格的权限,就算php 程序中存在漏洞,那么攻击者也只能篡改权限为 777 的目录,其它的文件是无法被改写的,网站不就就得更安全了吗?

核心总结:php-fpm 子进程所使用的用户,不能是网站文件所有者。 凡是违背这个原则,则不符合最小权限原则。

经过我参阅网上关于nginx, php-fpm 配置的文章教程和市面上的一些书籍,发现有不少人受这些文章的误导,直接让 php-fpm 子进程以网站所有者账号运行,例如张宴的《实战 nginx 取代 apache 的高性能 Web 服务器》一书的 52 页中,存在以下设置:
www
www

而在第50 页,设置网站文件所有者也为 www 用户:
chown -R www:www /data0/htdocs/blog
显然,此书的这部分内部,对初学者有误导,针对这个问题,我已经向本书作者发邮件,希望其能在第二版中进行强调声明,以免由于过度宽松的权限配置,造成一些安全隐患。

官方提供的配置文件中,php-fpm 子进程使用 nobody 用户,这完全是合理的,无须修改。

那么nginx 的子进程用户,如何设置合理? 我的建议是也使用 nobody (对错误日志写入等无影响),设置方法如下:
nginx.conf文件第一行设置为 user nobody; , 再执行 nginx -s reload 即可。

php-fpm子进程用户设置方法:
编辑文件php-fpm.conf (一般位于 /usr/local/php/etc/php-fpm.conf, 视安装参数为准),找到 user 、 group 两个参数的定义,将其设置为nobody( 默认已经是 nobody) ,再重启 php-fpm 进程即可。

网站可写目录的特殊注意
这里的可写,是相对php-fpm 子进程而言。一个网站最容易出安全问题的即是可写目录,如果可写目录权限能控制严格,安全系数也将大大提高。
我们认为,一个网站可写目录主要分为以下几种:
1.  php 数据缓存目录,如 discuz 的 forumdata 目录,就存放了大量数据缓存文件。此类目录一般会禁止用户直接访问,但是 discuz 在这个目录下又存放了不少 js, css 文件,我们并不能简单地拒绝用户访问这个目录。显然,这个目录下的所有文件,不能直接交给 php 解析,我们后面会给出解决方案。
2.  附件上传目录。显然此类目录需要开启访问,但不能交由php 引擎解析(即这个目录下的所有文件均视为普通静态文件)。
3.  静态文件生成目录,这类目录下的文件全部应视为静态文件。
4.  日志目录, 一般都会拒绝用户直接访问之。

也就是说对网站开发人员而言,需要对可写目录实现动静分离,不同性能的文件,应该区别对待之,这样也就方便系统管理员,设置合理的nginx 规则,以提高安全性。

简单地去掉php 文件的执行权限,并不能阻止 php-fpm 进程解析之。

接下来,根据以上总结,系统管理员如何配置nginx 的目录规则,才更安全呢?
1.  数据缓存目录 /cache/
这个目录的特点是需要777 权限,无须提供给用户访问,那么可以按以下参考配置 nginx
location ~ “^/cache” {
return 403;
}

location ~ “\.php$” {
fastcgi_pass 127.0.0.0:9000;
………………..
}

这时,任何用户将无法访问/cache/ 目录内容,即使
2. 附件上传目录 attachments
此目录的特点是需要开放访问权限,但所有文件不能由php 引擎解析(包括后缀名改为 gif 的木马文件)
location ~ “^/attachments” {

}

location ~ “\.php$” {
fastcgi_pass 127.0.0.0:9000;
………………..
}

注意,上面对attachments 目录的 location 定义中是没有任何语句的。 nginx 对正则表达式的 location 匹配优先级最高,任何一个用正则表达式定义的 location, 只要匹配一次,将不会再匹配其它正则表达式定义的 location 。

现在,请在attachments 目录下建立一个 php 脚本文件,再通过浏览器访问安,我们发现浏览器提示下载,这说明 nginx 把 attachments 目录下的文件当成静态文件处理,并没有交给 php fastcgi 处理。这样即使可写目录被植入木马,但因为其无法被执行,网站也就更安全了。

显然,重要的php 配置文件,请勿放在此类目录下。

3.  静态文件生成目录 public
这些目录一般都是php 生成的静态页的保存目录,显然与附件目录有类似之处,按附件目录的权限设置即可。
可以预见的是,如果我们设置了较严格的权限,即使网站php 程序存在漏洞,木马脚本也只能被写入到权限为 777 的目录中去,如果配合上述严格的目录权限控制,木马也无法被触发运行,整个系统的安全性显然会有显著的提高。

但是网站可写目录的作用及权限,只有开发人员最为清楚。这方面需要php 开发人员和系统管理员积极沟通。我们使用的方式是:项目上线前,开发人员根据以文档形式提供网站可写目录的作用及权限,由系统管理员针对不同目录进行权限设置。任何一方修改了网站目录权限,但未体现到文档中,我们认为是违反工作流程的。
原文:http://zhangxugg-163-com.iteye.com/blog/1171572

标签:PHP 发布于:2019-10-15 07:04:20