防范PHP命令注入的关键是建立输入到执行的完整信任链路:禁用高危函数、最小权限运行、优先使用原生函数或扩展替代shell调用,必须执行时严格用escapeshellarg包裹参数并隔离命令结构。

避免PHP命令注入漏洞,关键不是“少用system()”,而是建立输入到执行的完整信任链路——所有用户可控数据,只要进入系统命令上下文,就必须经过明确、分层、不可绕过的处理。
只在绝对必要时调用系统命令
多数业务场景其实不需要执行shell命令。文件操作可用PHP原生函数(file_get_contents、scandir)、网络请求可用cURL或file_get_contents配合stream context、压缩解压可用ZipArchive类。如果只是调用一个外部工具(如ImageMagick、ffmpeg),优先查是否有成熟PHP扩展或Composer包封装,而不是自己拼exec()。
必须调用时,严格区分参数与命令结构
命令注入的本质是用户输入突破了“参数边界”。防御核心是:让输入永远只出现在它该在的位置,且被正确包裹。
- 单个字符串参数(如文件名、关键词)→ 用escapeshellarg()包裹,再拼入命令,例如:exec("grep " . escapeshellarg($_GET['keyword']) . " /var/log/app.log");
- 整条命令含多个动态部分 → 先用escapeshellarg分别处理每个参数,再拼成完整命令,最后不加任何处理传给exec();不要对已escapeshellarg过的字符串再套escapeshellcmd
- 禁止把用户输入放在选项值位置(如--name=xxx),尤其不能直接拼接在等号后;若必须支持,应先白名单校验前缀(如只允许--format=json),再用--终止选项解析
从运行环境掐断高危能力
即使代码有疏漏,也能大幅降低危害。
立即学习“PHP免费学习笔记(深入)”;
- 在php.ini中禁用高危函数:disable_functions = system,exec,passthru,shell_exec,proc_open,popen,pcntl_exec
- 确保PHP以最小权限系统用户运行(如www-data),绝不用root或Administrator启动PHP-FPM或Apache模块
- Web目录禁止执行权限(Linux下chmod -x),上传目录禁用PHP解析(Nginx/Apache配置中明确拒绝.php后缀执行)
用更安全的替代方案代替shell调用
很多任务有比调用shell更可控、更可审计的实现方式。
- 需要执行外部程序?改用proc_open()并显式定义stdin/stdout/stderr管道,配合超时和资源限制
- 需要解析命令行输出?优先考虑JSON/CSV等结构化输出格式,并用json_decode()解析,而非正则提取文本
- 需要批量文件操作?用RecursiveDirectoryIterator + RegexIterator,而非ls | grep | awk组合



















