必须用hash_file('sha256', $_files'audio')在move_uploaded_file()前计算原始哈希,移动后立即比对,不一致则unlink并报错;仅校验size不可靠,上传目录需严格权限控制。

PHP上传音频时,move_uploaded_file() 本身不校验内容完整性,文件在传输或存储过程中被篡改(如中间人修改、磁盘损坏、并发写入冲突)是真实风险。防篡改 ≠ 防恶意上传,重点是确保“上传进来什么样,落盘后还是什么样”。
用 hash_file() 校验上传前后一致性
临时文件 $_FILES['audio']['tmp_name'] 在 PHP 接收后、移动前是唯一可信的原始副本。必须在此刻计算其哈希值,并与移动后的文件再次比对。
- 仅用
md5_file()或sha1_file()不够安全,建议用hash_file('sha256', $tmp_name) - 不要等文件移动完再算 —— 移动过程本身可能出错(如磁盘满、权限不足),导致部分写入
- 校验失败必须中止:删除已写入的目标文件,返回错误,不记录元数据
$tmp = $_FILES['audio']['tmp_name'];
$expectedHash = hash_file('sha256', $tmp);
$target = '/safe/storage/' . uniqid('audio_') . '.mp3';
if (move_uploaded_file($tmp, $target)) {
$actualHash = hash_file('sha256', $target);
if ($actualHash !== $expectedHash) {
unlink($target);
die('文件完整性校验失败:内容可能已被篡改');
}
} else {
die('移动临时文件失败');
}
避免依赖 $_FILES['audio']['size'] 做完整性判断
文件大小只是元信息,不能代表内容未变。攻击者可构造两个不同内容但相同大小的音频文件(碰撞攻击虽难,但大小一致 ≠ 内容一致),且 $_FILES['audio']['size'] 本身可能被伪造或截断(如 POST 数据被中间代理修改)。
-
$_FILES['audio']['size']只能用于初步过滤(如拒绝 0 字节或超限文件) - 真正校验必须基于二进制内容哈希,而非长度
- 如果业务要求强防篡改(如版权音频分发),应配合服务端签名或客户端预签名上传(如 S3 presigned URL)
上传路径和权限配置影响校验有效性
即使哈希校验通过,若目标目录可被其他进程/用户写入,文件后续仍可能被覆盖或追加。校验只管“刚落盘那一刻”,不管“之后是否被改”。
- 上传目录必须设置为仅 Web 进程可写(如
chown www-data:www-data+chmod 750) - 禁止该目录下任何脚本执行(Nginx/Apache 配置
deny all;或php_flag engine off) - 不要把音频直接放在 Web 根目录下 —— 即使校验通过,公开可读也不等于安全可改;访问应走代理脚本或 CDN 回源鉴权
最易被忽略的一点:哈希校验必须在 move_uploaded_file() 成功后立刻执行,且不能跨进程或异步做。PHP 的临时文件在请求结束时自动清理,错过这个窗口就再也拿不到原始输入了。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











