锁定父目录写权限是最直接有效的防删方式,因删除文件夹需父目录有写权限;chmod 755 或 750 父目录、路径白名单校验、chattr +a/+i 内核级防护及 --dry-run 机制共同构成多层防护。

用 chmod 锁定父目录权限是最直接有效的方式
文件夹本身删不掉,本质是因为操作系统需要对它的**父目录**有写权限——只要父目录不可写,哪怕文件夹是 777,你也删不掉它。
常见误操作是只改文件夹权限,结果没用;真正起作用的是上一级目录的 w 位。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 确认目标文件夹路径,比如
/var/www/uploads,那关键就是/var/www这个父目录 - 执行
chmod 755 /var/www(去掉组和其他人的写权限),或更保守地用chmod 750 /var/www(仅所有者可写) - 避免用
chmod -R直接套用到整个树,否则可能误锁子目录里本该可写的临时文件位置 - 如果用
www-data运行 PHP,确保该用户仍是父目录的所有者,否则会连创建文件都失败
PHP 代码里调用 unlink() 或 rmdir() 前必须校验路径白名单
靠系统权限只能防手动误删,防不住代码逻辑出错或被注入后主动删目录。很多 CMS 插件、上传模块、缓存清理脚本一不留神就递归删了 ../ 上去。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 所有涉及
rmdir()、unlink()、exec("rm -rf")的地方,先做路径规范化和白名单比对 - 用
realpath($path)获取绝对路径,再判断是否以允许的根目录开头,例如:if (strpos(realpath($path), '/var/www/public') !== 0) { die("非法路径"); } - 禁用
allow_url_fopen和allow_url_include,防止通过 URL 参数注入任意路径 - 不要依赖
$_GET['dir']或$_POST['path']直接拼进文件操作函数,哪怕加了basename()也不够——它不防../
Linux 下用 chattr +a 或 +i 是终极保险,但慎用
chattr 是内核级防护,比 chmod 更硬。但 PHP 进程通常没权限执行它,且一旦设错容易把自己也锁死。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
-
chattr +a允许追加但禁止删除/重命名,适合日志目录,不影响 PHP 写入 -
chattr +i真·不可删不可改,连 root 都要先chattr -i才能动——除非你真准备永久冻结这个目录,否则别轻易上 - PHP 无法直接调用
chattr,必须由运维在部署时用 shell 设置,且需确认文件系统支持(ext4/xfs 可,某些容器环境或 NFS 可能不认) - 设置后用
lsattr /path检查,别设完就忘——下次更新配置想删旧目录时会卡住
误删后恢复难,所以重点得放在“删之前拦住”
Linux 删除是直接 unlink,没回收站。extundelete 或 photorec 成功率低、耗时长、还可能覆盖原数据。与其事后抢救,不如让删除动作本身变困难。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 把敏感目录移到非 Web 根目录下,比如
/srv/app-data,和代码分离,降低被猜中路径的概率 - 开发环境默认启用
disable_functions = rmdir,unlink,exec,passthru,上线前按需放开,但保留对关键目录的限制 - 写个轻量钩子脚本监控
/var/log/auth.log或auditd日志,发现异常批量删除行为立刻告警 - 最实在的一条:所有自动化清理任务,强制加
--dry-run开关,默认只打印要删什么,人工确认后再跑真实版
权限、路径校验、内核属性这三层不是叠加越多越安全,而是得看谁在操作、在哪操作、删的代价有多大。一个被 PHP 脚本反复读写的上传目录,设 +i 就等于自废武功;而一个只存配置模板的 /etc/myapp/templates,chattr +i 几乎零成本。










