FrankenPHP 1.4 生产禁用危险函数唯一有效方式是精准配置php.ini的disable_functions,需分层禁用命令执行、动态代码、高危文件操作及信息泄露类函数,并结合只读文件挂载密钥、关闭display_errors等加固项。

FrankenPHP 1.4 生产部署中禁用危险函数,核心不是“加功能”,而是收缩 PHP 运行时能力边界——它本身不提供新安全开关,所有函数级控制仍依赖 php.ini 的 disable_functions,但必须结合 FrankenPHP 的运行模型做精准裁剪,否则易误伤或留空子。
✅ php.ini 中必须配置的 disable_functions(按风险分层)
disable_functions 是唯一生效入口,需在 php.ini-production 基础上追加。FrankenPHP 1.4 默认使用 /usr/local/etc/php/php.ini,修改后需重启服务(或 frankenphp stop-workers && caddy reload)。
命令执行类(绝对禁用)
防止任意命令执行、反弹 shell:system, exec, shell_exec, passthru, popen, proc_open, pcntl_exec, dl-
代码动态执行类(严格禁用)
阻断 eval 类绕过、反序列化链利用:eval, assert, create_function, call_user_func, call_user_func_array, preg_replace注意:
preg_replace含/e修饰符时可执行代码,PHP 7.3+ 已弃用但旧代码仍可能依赖,必须禁用。 -
文件系统操作类(按需收紧)
禁用非业务必需的高危操作,尤其避免目录遍历和权限篡改:show_source, highlight_file, symlink, link, parse_ini_file, ini_restore, chmod, chown, chgrp, copy, rename, unlink, rmdir, mkdir若项目需
copy()上传临时文件或rename()移动附件,可保留,但须确保路径白名单校验(如限定在/tmp/uploads/下)。立即学习“PHP免费学习笔记(深入)”;
-
信息泄露类(生产环境必禁)
防止调试接口暴露服务器结构、版本、磁盘状态:phpinfo, php_uname, getmyuid, getmypid, getmyinode, getcwd, diskfreespace, disk_free_space, disk_total_space特别检查是否已禁用
phpinfo():FrankenPHP 不拦截该函数,一旦被路由到info.php就全量泄露。
⚠️ FrankenPHP 特有风险点:不能只靠 disable_functions
禁用函数只是基础,FrankenPHP 的进程模型和配置方式会放大遗漏后果:
-
getenv()和$_SERVER不受disable_functions控制
即使禁用了getenv,$_SERVER['DB_PASSWORD']仍可被读取。因此:- 绝对不要通过环境变量传密钥(见下条)
- 禁用
putenv(加进disable_functions)防止运行时污染
-
Worker 模式下全局变量残留更危险
若某次请求中file_get_contents('/run/secrets/db.conf')后把密码存进static $db_pass,后续所有请求都可复用——此时禁用file_get_contents反而比禁用exec更关键。
建议:- 敏感值只在请求生命周期内加载(如封装进 Service 类的
__invoke()) - 避免
require_once加载含密钥的配置文件(会被 OPcache 缓存)
- 敏感值只在请求生命周期内加载(如封装进 Service 类的
-
Caddyfile 中禁止引用敏感变量
错误写法:php_server { env DB_PASSWORD }正确做法:用只读文件挂载 +
parse_ini_file(),且该函数未被禁用(若禁了,改用file()+array_shift()手动解析)。
? 密钥与配置传递:替代环境变量的安全方案
FrankenPHP 1.4 明确拒绝“注入”概念,只接受操作系统级隔离:
-
推荐:只读文件挂载(最稳妥)
宿主机:echo "DB_PASSWORD=xxx" > /etc/secrets/db.conf chmod 600 /etc/secrets/db.conf chown root:www-data /etc/secrets/db.conf
Docker 启动:
volumes: - /etc/secrets/db.conf:/run/secrets/db.conf:ro
PHP 中:
$conf = parse_ini_file('/run/secrets/db.conf', false); $password = $conf['DB_PASSWORD'] ?? ''; -
若必须用环境变量(如 PaaS 限制):
- 启动前
unset所有含SECRET|KEY|PASS|TOKEN的变量 - PHP 首次读取后立即
putenv('DB_PASSWORD=');并验证getenv('DB_PASSWORD') === false - 在
php.ini中补上putenv到disable_functions
- 启动前
? 补充加固项(非函数禁用,但直接影响安全水位)
-
display_errors = Off(防错误信息泄露路径、版本、SQL 结构) -
expose_php = Off(隐藏X-Powered-By头) -
allow_url_fopen = Off(防 SSRF 和远程文件包含) -
opcache.restrict_api = "/var/www/"(限制 OPcache API 访问路径,FrankenPHP 无等效指令,需手动配) - Caddyfile 中关闭
debug模式,禁用pprof插件(如有启用)
不复杂但容易忽略。



















