php无法直接防止文件夹篡改,必须通过系统权限、web服务器配置和部署隔离三类措施实现:限制www-data写权限、上传目录与web根分离、禁用危险函数、web服务器禁止执行上传目录php脚本、路径校验用白名单或realpath双重检查、chattr+i/a保护关键目录。

PHP中无法直接防止文件夹被篡改,权限控制必须在系统层
PHP本身是运行在Web服务器进程下的脚本语言,它没有能力“锁定”或“免疫”文件系统操作。所谓“防止篡改”,本质是限制www-data(或apache、nginx等)用户对目录的写权限。PHP代码里调用chmod()或chown()只能临时修改,且常因SELinux、容器环境或open_basedir限制而失败。
真正起效的措施只有三类:操作系统文件权限、Web服务器配置、部署流程隔离。下面按实际排查顺序说明关键动作:
- 确认Web服务进程用户(如
ps aux | grep apache2),再用ls -ld /path/to/dir核对该用户是否拥有写权限 - 非必要目录一律设为
755(目录)或644(文件),上传目录除外;上传目录应与Web根分离(如/var/www/uploads不放在/var/www/html内) - 禁用PHP危险函数:在
php.ini中设置disable_functions = exec,passthru,shell_exec,system,proc_open,popen,symlink,link,unlink,mkdir,rmdir,chmod,chown(注意unlink和mkdir会影响正常功能,需评估)
Apache/Nginx配置中禁止执行上传目录里的PHP脚本
攻击者上传shell.php后,最常见利用方式就是直接访问执行。仅靠PHP层过滤文件名或扩展名远远不够——绕过手段太多(.php5、.phtml、大小写.PhP、空字节等)。必须在Web服务器层面截断执行链。
Apache示例(放入.htaccess或虚拟主机配置):
立即学习“PHP免费学习笔记(深入)”;
<Directory "/var/www/html/uploads">
php_flag engine off
<FilesMatch "\.(php|phar|phtml|phps|php7)$">
Require all denied
</FilesMatch>
</Directory>
Nginx示例(server块内):
location ^~ /uploads/ {
location ~ \.php$ {
deny all;
}
}
注意:^~前缀确保该规则优先于正则匹配;若用alias而非root,路径匹配逻辑会不同,容易漏掉。
PHP代码中校验文件路径时,避免使用用户输入拼接file_get_contents()或include
典型漏洞模式:$file = $_GET['f']; include 'templates/' . $file . '.php'; —— 攻击者传f=../../etc/passwd%00就能读取系统文件(PHP 5.3.4+已默认忽略%00,但仍有其他绕过方式)。
安全做法不是“过滤点号和斜杠”,而是彻底切断路径拼接可能:
- 用白名单映射:如
$map = ['home' => 'home.tpl', 'about' => 'about.tpl']; $file = $map[$_GET['f']] ?? die('Invalid'); - 用
realpath()+dirname()双重校验:$real = realpath("templates/$user_input"); if (strpos($real, realpath('templates')) !== 0) die('Access denied'); - 绝对禁止将
$_FILES['xxx']['tmp_name']直接传给move_uploaded_file()以外的函数(如file_get_contents($_FILES['x']['tmp_name'])可能触发临时文件竞争)
Linux下用chattr +a或+i保护关键目录(需root权限)
chattr是比chmod更底层的保护机制,不受用户权限影响。对PHP项目中不变的配置目录(如config/)、框架核心目录(如vendor/),可加不可修改属性:
-
chattr +i /var/www/html/config:目录完全只读(连root都不能改,解除需chattr -i) -
chattr +a /var/www/html/logs:只允许追加(适合日志目录,PHP可fopen(..., 'a')但不能unlink或ftruncate)
注意:+i会导致Composer更新、缓存清理等运维操作失败;生产环境建议仅对config/、.env等极少数文件启用,且必须写入部署文档,否则后续维护会卡住。











