需从运行时环境、PHP配置与代码逻辑三层面协同控制:一、用chdir()切换至安全目录再执行;二、白名单校验路径并禁用危险字符;三、结合open_basedir与系统权限隔离;四、封装safe_exec函数过滤危险命令;五、使用Docker/chroot实现系统级隔离。

如果您在PHP中启用exec函数后,希望限制其仅能在特定目录下执行系统命令,防止命令注入或越权操作,则需从运行时环境、PHP配置与代码逻辑三层面协同控制。以下是实现该限制的多种方法:
一、使用chdir()在执行前强制切换工作目录
该方法通过在调用exec前显式切换至预设安全目录,使所有相对路径命令均以此目录为基准,降低跨目录执行风险。
1、在PHP脚本中定义允许的操作根目录,例如/var/www/html/safe-bin/。
2、调用chdir()函数将当前工作目录切换至该路径:chdir('/var/www/html/safe-bin/');
立即学习“PHP免费学习笔记(深入)”;
3、再执行目标命令,如exec('ls -l', $output, $return_code);。
4、执行完毕后可选择恢复原始目录(需提前getcwd()保存)或保持隔离状态。
二、对传入命令路径进行白名单校验与规范化
该方法在调用exec前严格解析并验证命令及其参数中的所有路径成分,确保不包含非法上层目录跳转或绝对路径引用。
1、使用realpath()获取命令中涉及文件或目录的绝对路径:$safe_path = realpath($user_input_path);
2、检查该路径是否以预设安全根目录开头:if (strpos($safe_path, '/var/www/html/allowed/') !== 0) { die('Access denied'); }
3、若命令含多个路径参数(如cp a.txt b.txt),需对每个参数单独执行上述校验。
4、禁用含..、~、$、反引号等可能引发路径逃逸的字符。
三、通过open_basedir配合系统用户权限隔离
该方法利用PHP内核级文件访问限制,并结合操作系统用户权限,使exec进程无法访问非授权目录下的资源。
1、在php.ini或虚拟主机配置中设置open_basedir = /var/www/html/allowed/:/tmp/,注意末尾斜杠。
2、确保Web服务器进程(如www-data)对该安全目录具有执行权限,但对其他敏感路径(如/etc/、/root/)无读写执行权限。
3、在exec调用中仅使用相对路径或白名单内绝对路径,避免触发open_basedir拦截。
4、验证效果:尝试执行exec('cat /etc/passwd', $out);应返回空数组且$return_code非零。
四、封装安全exec函数并禁用危险命令关键词
该方法通过自定义封装函数统一拦截高危指令,同时强制限定工作目录与参数格式,形成代码层防护屏障。
1、定义函数safe_exec($cmd, $allowed_dir = '/var/www/html/allowed/') {。
2、在函数内执行chdir($allowed_dir)并校验$allowed_dir是否为真实存在且合法的路径。
3、使用正则表达式过滤命令字符串:if (preg_match('/\b(rm|mknod|mount|su|sudo|chown|chmod)\b/i', $cmd)) { return false; }
4、调用escapeshellcmd()处理整个命令,再用escapeshellarg()包裹各参数,最后执行exec()。
五、使用Linux容器或chroot环境隔离PHP执行上下文
该方法在操作系统层面构建轻量级隔离环境,使PHP进程及其fork出的exec子进程始终受限于指定文件系统视图。
1、为Web应用部署专用Docker容器,挂载仅含/app/bin/和/tmp/的只读或受限读写卷。
2、在容器启动时以非root用户运行PHP-FPM,且该用户主目录与shell均被禁用。
3、配置容器security_opt: ["no-new-privileges:true"],阻止exec提升权限。
4、在PHP中调用exec时,所有路径自动映射至容器内受限视图,宿主机目录不可见。



















