P

PHP如何禁用危险函数?

Captain 杂类 2025-05-02

配置服务器时发现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