如何在Apache/PHP/Ubuntu环境中实现允许PHP文件执行但禁止读取其源码?
嘿,这个问题问得很实际——既要让PHP文件能正常执行(包括被其他脚本包含),又要防止恶意或误操作的脚本读取源码,还不想搞复杂的函数黑白名单。我来给你梳理几个在Ubuntu+Apache+PHP环境下可行的配置方案:
方案一:利用文件权限+细粒度ACL(有局限性)
首先,我们可以通过Linux文件系统权限做基础限制,但要注意核心前提:PHP进程(不管是mod_php的Apache进程,还是PHP-FPM进程)必须能读取文件才能执行它,直接锁死权限肯定不行。具体操作:
- 将
secret.php的所有者设为root,权限设为0600,这样只有root用户能直接读取它。 - 给PHP的运行用户(比如默认的
www-data)添加ACL权限,允许它读取这个文件:setfacl -m u:www-data:r /path/to/secret.php
不过这个方案有局限:如果custom.php和secret.php是同一个PHP进程运行的,那custom.php用file_get_contents还是能读取secret.php,因为进程本身有读权限。它只能防止其他系统用户读取文件,没法阻止同进程的PHP脚本。
方案二:用PHP的open_basedir做路径隔离(需调整文件结构)
如果能调整文件目录结构,open_basedir是个不错的选择——它能限制PHP脚本只能访问指定的目录:
- 把
secret.php放到独立的安全目录,比如/var/www/secure/,custom.php放在业务目录/var/www/public/。 - 在Apache配置文件(比如
000-default.conf)中,给两个目录分别设置open_basedir:# 限制public目录下的脚本只能访问自身和临时目录 <Directory /var/www/public/> php_admin_value open_basedir "/var/www/public/:/tmp/" </Directory> # 允许secure目录下的脚本访问自身目录 <Directory /var/www/secure/> php_admin_value open_basedir "/var/www/secure/:/tmp/" </Directory>
这里有个小问题:如果custom.php需要包含secret.php,这个配置会阻止它,因为public目录的脚本无权访问secure目录。解决办法是把secret.php的核心逻辑封装成PHP扩展(编译成.so文件),这样custom.php可以通过加载扩展使用功能,而不需要读取源码。编译扩展需要一点Linux基础,但不算特别复杂。
方案三:使用AppArmor做强制访问控制(精确但需配置)
Ubuntu默认的AppArmor安全模块可以实现更精确的控制,比如允许PHP进程读取secret.php用于执行,但限制普通读取操作:
- 先确保AppArmor已启用:
sudo systemctl enable --now apparmor - 复制现有PHP-FPM的AppArmor配置作为模板(以PHP 8.2为例):
sudo cp /etc/apparmor.d/usr.sbin.php-fpm8.2 /etc/apparmor.d/usr.sbin.php-fpm8.2-custom - 编辑配置文件,添加针对
secret.php的规则:# 允许读取secret.php用于执行 /path/to/secret.php r, # 可以结合少量函数禁用,比如禁止file_get_contents这类直接读取函数
不过要注意,AppArmor很难区分PHPinclude和file_get_contents的底层读取行为,所以可能需要配合禁用一两个核心读取函数,这比全量黑白名单简单得多。
方案四:加密PHP源码(最直接但需工具)
如果上面的配置都不能满足需求,最直接的办法就是加密secret.php源码,比如用ionCube或Zend Guard这类工具。加密后的文件只能被PHP解析执行,即使被读取也只是乱码,完全看不到源码。这类工具部分需要付费,部署时要安装对应的加载器,但配置好后完全不用担心源码泄露。
总结一下:如果不想碰函数黑白名单,优先考虑调整文件结构配合open_basedir,或者用加密工具;如果能接受少量函数禁用,结合AppArmor会更灵活。
备注:内容来源于stack exchange,提问作者Hugo Delsing

