文章总结: 本文系统解析PHP文件上传、遍历及包含等操作的安全风险,指出路径拼接与过滤缺失是主要隐患。通过Rrzcms、Metinfo等代码审计案例,剖析任意文件读取与包含漏洞成因。文章提出严格过滤输入、实施白名单、利用realpath校验路径及配置open_basedir等关键防御措施,为构建安全的文件操作机制提供实战指导。 综合评分: 84 文章分类: 代码审计,WEB安全,安全开发
第32天-PHP文件安全操作全解析:从基础函数到代码审计案例
原创
萧瑶 萧瑶
AlphaNet
2026年2月15日 12:44 韩国
在Web开发中,文件操作是极其常见的需求——上传头像、下载附件、读取配置文件、包含模板文件……然而,文件操作也是安全漏洞的高发区。本文将系统梳理PHP中与文件相关的核心操作(上传、下载、读取、删除、遍历、包含),剖析每个环节的安全风险,并结合三个真实代码审计案例,带你深入理解文件安全的攻防之道。
一、文件上传:$_FILES 与 move_uploaded_file
PHP通过预定义超全局变量 $_FILES 处理上传文件。当表单设置 enctype=”multipart/form-data” 并提交后,服务器会生成一个包含文件信息的数组。
1.1 $_FILES 结构
键名 说明
$_FILES[“表单name”][“name”] 客户端文件原始名称
$_FILES[“表单name”][“type”] 文件的MIME类型(由浏览器提供,不可信)
$_FILES[“表单name”][“size”] 文件大小(字节)
$_FILES[“表单name”][“tmp_name”] 服务器端临时存储的路径
$_FILES[“表单name”][“error”] 上传错误代码(0表示成功)
1.2 文件保存函数 move_uploaded_file
move\_uploaded\_file($\_FILES['file']['tmp\_name'], 'uploads/' . $\_FILES['file']['name']);
该函数会检查临时文件是否真的是通过HTTP POST上传的,避免直接操作本地文件。
1.3 安全风险与防护
· 文件类型绕过:仅靠MIME类型不可靠,应结合文件内容头、扩展名白名单。
· 文件大小限制:通过 upload_max_filesize 和 post_max_size 控制。
· 存储路径防护:避免用户控制文件名或路径,防止路径遍历(如 ../)。
· 重名处理:使用 uniqid() 或时间戳生成随机文件名,避免覆盖。
二、文件遍历与读取:目录操作函数
2.1 目录遍历常用函数
· opendir() / readdir() / closedir():手动遍历目录。
· scandir():一次性返回目录下所有文件和目录的数组。
· is_dir():判断路径是否为目录。
· is_file():判断是否为文件。
示例:递归列出目录下所有文件
function listFiles($dir) {
$files = scandir($dir);
foreach ($files as $file) {
if ($file == '.' || $file == '..') continue;
$path = $dir . '/' . $file;
if (is\_dir($path)) {
listFiles($path); // 递归子目录
} else {
echo $path . "\n";
}
}
}
2.2 安全限制:open_basedir
open_basedir 是php.ini中的指令,用于限制PHP只能访问指定目录及其子目录,防止脚本跨目录读取敏感文件。
ini\_set('open\_basedir', \_\_DIR\_\_); // 当前脚本所在目录
即便代码中存在文件包含漏洞,攻击者也无法越权访问其他目录。
2.3 目录遍历漏洞
如果程序直接拼接用户输入的文件名,攻击者可传入 ../../etc/passwd 读取系统文件。防御措施:
· 对用户输入进行过滤(如禁止 ..)。
· 使用 realpath() 获取绝对路径并验证是否在允许的基目录内。
三、文件删除:unlink 与命令执行风险
3.1 基础删除
unlink('path/to/file'); // 删除文件
rmdir('path/to/dir'); // 删除空目录
3.2 命令执行删除
某些开发者会用系统命令删除文件:
system("rm -rf " . $file); // 危险!
若 $file 可被用户控制,攻击者可注入额外命令(如 ; cat /etc/passwd)或删除整个目录。永远不要直接将用户输入拼接到系统命令中,应使用PHP原生函数。
四、文件下载:强制下载与HTTP头
通过设置HTTP响应头,可以强制浏览器下载文件而不是直接显示。
$file = 'path/to/secret.pdf';
if (file\_exists($file)) {
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . basename($file) . '"');
header('Content-Length: ' . filesize($file));
readfile($file);
exit;
}
关键点:
· basename() 避免路径信息泄露。
· 检查文件是否存在及权限,防止任意文件下载漏洞。
五、文件读取:file_get_contents 与 fopen 族
5.1 常用读取函数
· file_get_contents(‘file.txt’):将整个文件读入字符串。
· fopen() + fread():分块读取大文件。
· file():将文件按行读入数组。
5.2 任意文件读取漏洞
如果文件名参数来自用户输入且未过滤,攻击者可读取任意文件(如 ../../config.php)。防护思路同目录遍历。
六、文件包含:include / require 的隐患
文件包含是PHP中非常灵活的特性,但也带来了本地文件包含(LFI)和远程文件包含(RFI)漏洞。
6.1 常见包含函数
include 'header.php';
require\_once 'config.php';
6.2 文件包含漏洞成因
当文件路径由用户参数拼接且未严格过滤时,攻击者可利用 ../ 或绝对路径包含任意文件。
// 漏洞示例
$page = $\_GET['page'];
include($page . '.php');
若攻击者传入 ../../etc/passwd%00,利用空字节截断(PHP<5.3)即可读取敏感文件。
6.3 防御措施
· 使用白名单控制允许包含的文件。
· 禁用远程文件包含(allow_url_include=Off)。
· 对用户输入进行严格过滤,避免路径穿越。
七、代码审计案例:从漏洞看安全实践
案例1:Rrzcms遍历读取漏洞
来源:https://xz.aliyun.com/t/10932
漏洞点:后台某功能在读取目录时未对 .. 过滤,导致攻击者可遍历任意目录,读取敏感文件。
修复:使用 realpath() 限制访问路径必须在指定目录下。
案例2:Metinfo文件下载漏洞
来源:https://mp.weixin.qq.com/s/te4RG0yl_truE5oZzna3Eg
漏洞点:下载功能直接拼接用户传入的文件名,未校验路径,导致任意文件下载。
修复:对文件参数进行白名单验证,或使用加密后的文件ID映射真实路径。
案例3:Xhcms文件包含漏洞
来源:https://xz.aliyun.com/t/11310
漏洞点:模板渲染时动态包含文件,未过滤用户输入,导致本地文件包含,可读取配置文件或执行PHP代码。
修复:禁用远程包含,并使用 basename() 与白名单结合。
八、总结:文件安全的核心原则
-
永远不要信任用户输入:文件路径、名称等必须经过严格过滤。
-
最小权限原则:文件存储目录权限尽可能低,防止被恶意脚本利用。
-
使用白名单:对于上传、下载、包含等操作,优先使用白名单限制。
-
善用PHP内置函数:如 move_uploaded_file、basename、realpath 等,它们能帮助避免常见错误。
-
配置安全:合理设置 open_basedir、disable_functions 等php.ini选项,增加攻击难度。
文件操作是Web应用不可或缺的部分,但每一个函数都可能成为攻击者的突破口。希望本文能帮助你建立文件安全的基本认知,在实际开发中做到“防患于未然”。
参考资料
· PHP官方文档 – 文件系统函数
· OWASP – File Inclusion
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:AlphaNet 萧瑶 萧瑶《第32天-PHP文件安全操作全解析:从基础函数到代码审计案例》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。










评论