透過 disable_functions 指令禁用高風險函數,是 PHP 伺服器加固的核心措施之一。本文提供生產環境建議禁用清單、配置方法與驗證方式。
; php.ini
disable_functions = 函數名1,函數名2,函數名3
; 以逗號分隔,不區分大小寫,不受 safe_mode 影響
exec,passthru,shell_exec,system,proc_open,proc_close,proc_get_status,proc_nice,proc_terminate,popen,pclose,pcntl_exec
eval,assert,create_function
fopen,fwrite,fread,file_get_contents,file_put_contents,readfile,file,unlink,rename,copy,mkdir,rmdir,chmod,chown,chgrp,touch,symlink,link,readlink,tempnam,tmpfile
> 注意:此類函數若全部禁用會導致大多數框架 (Laravel、Symfony、ThinkPHP) 無法運作。建議採用 open_basedir 限制目錄而非完全禁用,或僅禁用最高風險的 unlink,rename,chmod,symlink。
phpinfo,phpversion,php_ini_loaded_file,php_ini_scanned_files,php_sapi_name,php_uname,php_os,phpcredits,php_logo_guid,php_egg_logo_guid,php_real_logo_guid,zend_version,zend_logo_guid,zend_thread_id
fsockopen,pfsockopen,stream_socket_client,stream_socket_server,stream_context_create,curl_exec,curl_multi_exec
> 注意:禁用 curl 會影響 API 串接、Composer、框架 HTTP Client。建議保留 curl,改用防火牆限制出站連線。
; php.ini 生產環境建議
disable_functions = exec,passthru,shell_exec,system,proc_open,proc_close,proc_get_status,proc_nice,proc_terminate,popen,pclose,pcntl_exec,eval,assert,create_function,phpinfo,phpversion,php_ini_loaded_file,php_ini_scanned_files,php_sapi_name,php_uname,php_os,phpcredits,php_logo_guid,php_egg_logo_guid,php_real_logo_guid,zend_version,zend_logo_guid,zend_thread_id,symlink,link,readlink
php.ini (確認 Loaded Configuration File 路徑)systemctl restart php-fpm 或 apachectl restartphp -r "var_dump(function_exists('exec'));" → 應輸出 bool(false)php -r "phpinfo();" | grep disable_functions在 php-fpm.conf 或 Apache VirtualHost 中覆蓋:
; PHP-FPM pool 設定 (www.conf)
php_admin_value[disable_functions] = exec,passthru,shell_exec,system,eval,assert
; Apache VirtualHost
php_admin_value disable_functions "exec,passthru,shell_exec,system,eval,assert"
| 問題 | 解決方案 |
|---|---|
| Composer 安裝套件失敗 | Composer 需 proc_open、proc_close、exec,建構階段暫時註釋禁用或使用 --no-scripts |
| Laravel/Symfony 快取清除失敗 | 框架部署腳本常用 exec 執行指令,建議 CI/CD 階段單獨環境或改用 PHP 原生操作 |
| 共享主機無法修改 php.ini | 使用 .user.ini (PHP 5.3+ 支援) 或聯繫主機商 |
| 函數仍可用 | 確認修改正確的 php.ini (CLI vs FPM 可能不同)、重啟服務、檢查是否被 pool 設定覆蓋 |
; php.ini
open_basedir = /var/www/html/:/tmp/:/var/lib/php/sessions/
; 或 PHP-FPM pool
php_admin_value[open_basedir] = /var/www/html/:/tmp/
限制 PHP 檔案操作範圍,防止目錄遍歷攻擊讀取 /etc/passwd 等敏感檔案。