配置服务器时发现PHP的某些函数可能被恶意利用执行系统命令,则需要禁用这些危险函数以防止安全漏洞。本文是针对此类问题的安全配置步骤,以下使用 disable_functions 指令在 php.ini 中禁用危险函数。
1️⃣ 常用禁用函数列表
ini
# php.ini 中配置
disable_functions = exec,system,passthru,shell_exec,proc_open,proc_close,proc_get_status,proc_nice,proc_terminate,popen,pcntl_exec
# 更严格的配置(推荐)
disable_functions = exec,system,passthru,shell_exec,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source,pcntl_exec,pcntl_fork,pcntl_wait,pcntl_waitpid,pcntl_wexitstatus,pcntl_wifexited,pcntl_wifsignaled,pcntl_wifstopped,pcntl_wstopsig,pcntl_wtermsig,assert
2️⃣ 配置步骤
1Panel系统
网站 -> 运行环境 -> PHP -> 更多 -> 配置 -> 禁用函数
#将以下函数复制到输入框内,函数之间用英文逗号隔开
system,exec,passthru,shell_exec,popen,proc_open,pcntl_exec
堡塔系统
软件商店 -> PHP -> 设置 -> 禁用函数
#将以下函数复制到输入框内,函数之间用英文逗号隔开并保存
system,exec,passthru,shell_exec,popen,proc_open,pcntl_exec
手工设置
找到 php.ini 文件
# Linux/Mac
php --ini
# 或
php -i | grep "Loaded Configuration File"
# 查找配置文件位置
find /etc -name "php.ini" 2>/dev/null
编辑 php.ini
bash
sudo vim /etc/php/8.2/cli/php.ini # CLI 模式
sudo vim /etc/php/8.2/apache2/php.ini # Apache 模式
sudo vim /etc/php/8.2/fpm/php.ini # PHP-FPM 模式
修改配置
ini
; 禁用多个函数(用逗号分隔)
disable_functions = exec,system,shell_exec,passthru
; 如果需要禁用更多
disable_functions = exec,system,passthru,shell_exec,proc_open,popen,curl_exec,curl_multi_exec,show_source
重启服务
bash
# Apache
sudo systemctl restart apache2
# 或
sudo service apache2 restart
# Nginx + PHP-FPM
sudo systemctl restart php8.2-fpm
sudo systemctl restart nginx
# 查看生效情况
php -m | grep -i disable_functions
3️⃣ 验证是否生效
方法1:创建测试文件
php
<?php
// test.php
if(function_exists('exec')) {
echo "exec 函数可用";
} else {
echo "exec 函数已被禁用";
}
?>
方法2:命令行检查
php -r "var_dump(function_exists('exec'));"
# 输出: bool(false) 表示已禁用
4️⃣ 针对不同环境的配置
虚拟主机/共享主机(无法修改 php.ini)
php
// .htaccess (仅 Apache + mod_php)
php_value disable_functions exec,system,passthru
// 或在 PHP 代码中(但某些函数无法运行时禁用)
// 注意:这不会真正禁用,只是检查
if(ini_get('disable_functions')) {
$disabled = explode(',', ini_get('disable_functions'));
}
Docker 环境
dockerfile
# Dockerfile
FROM php:8.2-fpm
RUN sed -i 's/disable_functions =.*/disable_functions = exec,system,passthru,shell_exec/' /usr/local/etc/php/php.ini-production
运行时修改(无效)
php
<?php
// ⚠️ 注意:这样不能禁用函数!
ini_set('disable_functions', 'exec'); // 无效
5️⃣ 完整安全配置示例
ini
# /etc/php/8.2/cli/conf.d/security.ini
; 禁用危险函数
disable_functions = exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source,pcntl_exec,pcntl_fork,pcntl_wait,pcntl_waitpid,pcntl_wexitstatus,pcntl_wifexited,pcntl_wifsignaled,pcntl_wifstopped,pcntl_wstopsig,pcntl_wtermsig,assert
; 禁用危险类
disable_classes = PDO,PHPUnit_Util_InvalidArgumentHelper
; 限制文件访问
open_basedir = /var/www/html:/tmp
; 禁用远程文件包含
allow_url_fopen = Off
allow_url_include = Off
; 显示错误但不暴露路径
display_errors = Off
display_startup_errors = Off
log_errors = On
6️⃣ 常见问题
Q: 禁用了 exec 但网站功能受影响怎么办?
php
// 方案1:使用白名单机制
function safe_exec($command) {
$allowed_commands = ['ls -l', 'date'];
if(in_array($command, $allowed_commands)) {
return exec($command);
}
throw new Exception("Command not allowed");
}
// 方案2:使用其他替代方案
// 尽量不要依赖 exec 类函数
Q: 如何临时启用某个函数?
php
// 可以在代码中检查
if(!function_exists('exec')) {
// 使用替代方案
function my_exec($cmd) {
// 使用 shell_exec 或其他替代
return shell_exec($cmd);
}
}
安全建议
| 函数 | 危险程度 | 是否需要禁用 | 原因 |
|---|---|---|---|
| exec() | 🔴 高危 | ✅ 必须 | 执行系统命令 |
| system() | 🔴 高危 | ✅ 必须 | 执行系统命令并输出 |
| shell_exec() | 🔴 高危 | ✅ 必须 | 执行 shell 命令 |
| passthru() | 🔴 高危 | ✅ 必须 | 执行命令并输出原始数据 |
| proc_open() | 🔴 高危 | ✅ 必须 | 更复杂的进程控制 |
| popen() | 🟠 中危 | ✅ 推荐 | 双向管道通信 |
| curl_exec() | 🟡 低危 | ⚠️ 视情况 | 可能导致 SSRF |
| assert() | 🟠 中危 | ✅ 推荐 | 字符串执行 |
总结
✅唯一正确方法:修改 php.ini 中的 disable_functions项
✅必须重启 PHP 服务才能生效
✅测试验证:使用 function_exists() 或命令行检查
✅生产环境建议:至少禁用 exec, system, shell_exec, passthru
