必须用finfo_open()校验音频文件真实MIME类型,结合白名单(audio/mpeg、audio/wav等)、重命名剥离原始名、上传目录隔离与禁用脚本执行、大小数量双控及元数据扫描五重防护,缺一不可。

不能只靠扩展名或 $_FILES['file']['type'] 判断音频文件是否安全——这两项全由客户端控制,可被任意伪造。
用 finfo_open() 校验真实 MIME 类型
浏览器提交的 $_FILES['file']['type'](如 audio/mpeg)毫无可信度;必须读取文件二进制头来确认类型。PHP 的 finfo_open() 是唯一靠谱手段。
- 先检查
$_FILES['file']['error'] === UPLOAD_ERR_OK,确保上传无底层错误 - 调用
finfo_open(FILEINFO_MIME_TYPE),传入$_FILES['file']['tmp_name'](不是原始路径) - 白名单只保留真正安全的音频类型:
audio/mpeg、audio/wav、audio/ogg、audio/flac,拒绝audio/x-php、text/plain等一切非纯音频类型 - 注意:
audio/mp4和video/mp4本质相同,若业务只收音频,应额外用getid3或ffprobe检查是否含视频轨道
重命名时强制剥离原始扩展名与路径
攻击者常传 shell.php.mp3 或 ../../etc/passwd.wav,直接使用 $_FILES['file']['name'] 会触发路径遍历或解析漏洞。
- 完全丢弃
pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION),不参与新文件名生成 - 用
uniqid('audio_') . bin2hex(random_bytes(6))生成前缀,再根据确认的 MIME 类型映射固定后缀(如audio/mpeg→.mp3) - 最终文件名中禁止出现
/、\、..、空格、控制字符;可用preg_replace('/[^a-zA-Z0-9._-]/', '', $filename)清洗(但更推荐彻底不用原始名) - 目标路径必须是绝对路径,且不在 Web 根目录下(如
/var/www/uploads/audio/应设为/srv/app/uploads/audio/)
move_uploaded_file() 前必须做大小与数量双控
单个大音频文件可能耗尽磁盘或内存;批量上传若不限制,容易演变为 DoS 攻击入口。
-
php.ini 中设
upload_max_filesize = 10M和post_max_size = 12M,并重启服务(仅代码层限制无效) - 脚本内二次校验:
if ($_FILES['file']['size'] > 10 * 1024 * 1024) { die('File too large'); } - 若支持多文件上传,用
count($_FILES['files']['name'])限制总数(如最多 5 个),并逐个校验 - 临时文件
$_FILES['file']['tmp_name']必须在move_uploaded_file()后立即失效,不要留作后续处理
上传目录需禁用脚本执行且隔离访问
即使文件内容看似安全,Web 服务器配置错误仍可能导致音频文件被当作 PHP 解析(例如 Apache 的 AddType application/x-httpd-php .mp3)。
- 上传目录物理路径必须脱离 Web 可访问范围;若必须放 Web 目录下,用
.htaccess(Apache)或location块(Nginx)禁止所有脚本执行 - 示例 Apache 配置:
<filesmatch> SetHandler default-handler </filesmatch> - 避免使用
chmod 777;目录权限建议755,文件权限644 - 生产环境禁用
allow_url_include和enable_dl,防止通过其他漏洞加载恶意模块
最易被忽略的是:音频文件本身可嵌入恶意元数据(如 ID3v2 标签里藏 PHP 代码),或作为容器携带隐藏 payload。若业务对安全性要求极高,应在移动后调用 ffprobe -v quiet -show_entries format_tags=comment -of default=nw=1 扫描标签,并过滤掉含可疑关键字(eval、system、)的字段。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











