echo框架需用finfo_file()校验文件真实mime类型,因$_files'file'由浏览器提交且可篡改;校验必须在move_uploaded_file()前完成,并配合扩展名白名单实现双校验。

Echo 框架本身不提供文件 MIME 类型检测能力,必须在 handler 中调用 PHP 的 finfo_file() 或 mime_content_type() 做真实类型校验——仅靠 $_FILES['file']['type'] 或扩展名是无效且危险的。
为什么不能信 $_FILES['file']['type']
这个字段完全由浏览器提交,可被任意篡改。比如把木马文件重命名为 shell.jpg,再伪造请求头 Content-Type: image/jpeg,服务端若只检查这个值就会放行。
- 它不读文件内容,只反射客户端声明
- PHP 官方文档明确标注该字段“不可信”
- 攻击者用 Burp Suite、curl 或自写脚本都能轻松绕过
用 finfo_file() 读取文件头做真实检测
这是目前最可靠的方式:打开临时文件($_FILES['file']['tmp_name']),用 libmagic 库解析前几百字节,返回真实 MIME 类型。
Echo框架 5.1.0 版本源码包下载,适合关注 RealIP 行为变化、StartConfig.Listener、NewDefaultFS 和观测性中间件入口的开发团队。
- 必须传入
FILEINFO_MIME_TYPE模式,避免返回带编码的完整字符串(如image/jpeg; charset=binary) - 务必检查
finfo_open()是否成功,失败时应拒绝上传(某些容器环境可能未启用 fileinfo 扩展) - 示例代码片段:
$finfo = finfo_open(FILEINFO_MIME_TYPE);
if (!$finfo) {
return echo.NewHTTPError(http.StatusInternalServerError, "MIME detection unavailable");
}
$mimeType = finfo_file($finfo, $_FILES['file']['tmp_name']);
finfo_close($finfo);
if (!in_array($mimeType, ['image/jpeg', 'image/png', 'video/mp4'], true)) {
return echo.NewHTTPError(http.StatusBadRequest, "Unsupported file type");
}
注意 move_uploaded_file() 后无法再用 finfo_file()
PHP 的 move_uploaded_file() 会清空临时文件,一旦调用就再也读不到原始内容。所有 MIME 校验必须在 move 之前完成。
- 顺序错误是常见坑:先
move_uploaded_file(),再想用finfo_file()检查——此时返回 false 或空字符串 - 如果业务逻辑需要保存后再校验(如异步扫描),得用
file_get_contents()或流式重读,但大文件会吃内存 - 更安全的做法是:校验通过 → 生成唯一文件名 →
move_uploaded_file()→ 存数据库
扩展名白名单 + 真实 MIME 双校验才是生产标配
单靠 MIME 检测也有局限:某些格式(如 SVG、PDF)头部特征容易被构造绕过;而纯扩展名校验又太弱。两者叠加才能覆盖多数攻击面。
- 先用
pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION)提取扩展名,查白名单(如['jpg', 'jpeg', 'png', 'mp4']) - 再用
finfo_file()检查真实类型,确保image/jpeg对应.jpg,而非.php - 特别注意视频类文件:
getimagesize()对.mp4返回 false,不能用于判断;必须用finfo
真实 MIME 检测不是可选项,是上传路径里第一个必须卡死的关卡。漏掉这步,后面所有权限控制、目录隔离、文件重命名都形同虚设。










