![在用户目录中保护 PHP](https://linux22.com/image/1429215/%E5%9C%A8%E7%94%A8%E6%88%B7%E7%9B%AE%E5%BD%95%E4%B8%AD%E4%BF%9D%E6%8A%A4%20PHP.png)
我是我们大学的一个小型服务器的系统管理员,学生们可以使用该服务器随意进行实验和运行长时间作业。
我在用户目录中启用了 PHP,以便他们可以轻松地试验网站。
最近,我发现用户目录中的所有 PHP 代码均由 Web 服务器用户 (www-data) 运行,该用户拥有一些我显然不想授予用户的权限。存在漏洞的网站或恶意用户可能会删除服务器的常规网站。
有没有办法用用户的权限运行用户的 PHP?
我想到了一个解决方法,即几乎不授予 Web 服务器任何权限,这样入侵就不会造成任何严重后果。这在我的处境下是可行的,因为网站非常简单(纯 HTML 索引)。
该服务器运行的是带有 Apache 2.4.10 的 Debian Jessie。
答案1
我已经使用 nginx、lighttpd 和 apache 多次完成此操作。它们的概念基本相同:以用户身份运行的 [快速]CGI 进程。
如果您想省去很多麻烦,请尝试像其他人建议的那样弄乱权限。特别是,如果您的用户网站由用户拥有,而您的主站点由 root 或类似人员拥有,那么您将处于良好的状态。但用户仍然不会被隔离,并且可以读取彼此的文件等(数据库密码?)。为每个用户/站点运行单独的虚拟服务器将为您提供最大的安全性,并且它肯定比尝试使用 apache 隔离用户更简单。
在 apache 中,隔离 PHP 用户的标准方法是通过 SuExec(还有 mpm-itk)。如果你在 Google 上搜索apache fastcgi suexec
或类似内容,你应该会得到很多结果。我认为将满的此处提供了说明。它可能因各种设计决策和使用的发行版而异。相反,我将尝试提供一些我认为重要的要点以及我的配置的简要说明。我的设置非常复杂(除此之外,我还运行了一个自定义 SELinux 模块)。以下是 [希望] 简要概述:
- 通过将 *.somedomain 指向服务器来实现基于名称的虚拟主机:user.somedomain 是虚拟主机的名称(我假设您可以对用户目录执行同样的事情?)。
/etc/httpd/vhosts.d/user.conf
每个用户一个。/var/www/vhosts_config
每个用户 一个目录。/var/www/vhosts_config/$USER/wrapper-bin
包含执行 PHP 的包装器(稍后会详细介绍)/var/www/vhosts_config/$USER/php/php.ini
:我喜欢php.ini
每个用户都有单独的帐户。/var/www/vhosts_config/$USER/php/ext/*.ini
:每个可用扩展一个 ini 文件/var/www/vhosts_config/$USER/php/ext-active/*.ini
:每个启用的扩展的符号链接../ext
(所以我也可以为每个用户启用/禁用扩展)
/var/www/vhosts/user
包含 vhost 的实际内容。我建议始终使用public_html
子目录作为文档根目录,以便用户拥有文档根目录之外的目录来存储配置文件等。- 用户不应该能够读彼此的文件。您需要允许
+x
用户访问 Web 服务器。有多种方法可以做到这一点。我使用 POSIX ACL。
每个用户的 httpd 配置看起来像这样(为简洁起见有所改变):
<VirtualHost *:80>
ServerName someuser.somedomain
DocumentRoot /var/www/vhosts/someuser/public_html
SuexecUserGroup someuser someuser
FcgidWrapper /var/www/vhosts_config/someuser/wrapper-bin/php .php
#max of 5 cgis per vhost
FcgidMaxProcessesPerClass 5
FcgidMinProcessesPerClass 0
AddHandler php-fcgi .php
Action php-fcgi /wrapper-bin/php
Alias /wrapper-bin/ /var/www/vhosts_config/someuser/wrapper-bin/
<Location /wrapper-bin/>
Options +ExecCGI
SetHandler fcgid-script
</Location>
</VirtualHost>
suexec
是setuid
apache 调用以作为给定用户启动进程的根程序。它非常挑剔。它要求它执行的程序由用户拥有,并包含在用户/var/www
拥有的目录的子目录中(这在不同的 Linux 发行版上有所不同,并在编译时设置)。这就是为什么每个用户都需要自己的 PHP 包装器脚本。
/var/www/vhosts_config/someuser/wrapper-bin/php
看起来像:
export PHPRC=/var/www/vhosts_config/someuser/php
export PHP_INI_SCAN_DIR=$PHPRC/ext-active/
export PHP_FCGI_CHILDREN=0
umask 0077
exec /usr/bin/php-cgi
PHP_INI_SCAN_DIR
设置一个目录来查找其他php.ini
文件,我用它来加载特定于扩展的配置。PHPRC
列出在其中查找php.ini
文件的目录。
你不有为每个用户使用单独的 PHP 配置,这样做肯定会使事情变得复杂。我喜欢为用户提供精简的配置,只启用必要的配置(默认情况下启用一些常用扩展)。我还为每个用户加载了具有不同配置的 suhosion(不同的加密密钥)。