最可靠的做法是用python-magic通过文件头部“魔数”识别真实MIME类型,因其不依赖扩展名、覆盖广、准确率高;Windows需装python-magic-bin,macOS/Linux需先装系统libmagic;用magic.Magic(mime=True).from_file()获取标准MIME字符串。

用 python-magic 检测真实 MIME 类型最可靠
仅靠文件扩展名判断格式完全不可信,比如把 photo.jpg 改成 photo.pdf 不会改变内容。真正有效的办法是读取文件头部字节(即“魔数”),匹配已知签名。python-magic 是 libmagic 的 Python 封装,底层和 file 命令一致,准确率高、覆盖广。
安装时注意:Windows 用户需额外安装 libmagic 二进制依赖(推荐用 pip install python-magic-bin);macOS/Linux 直接 pip install python-magic 即可,但确保系统已装 libmagic(如 macOS 上 brew install libmagic)。
基本用法示例:
import magic
m = magic.Magic(mime=True)
mime_type = m.from_file("document.docx") # → "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
-
mime=True返回标准 MIME 字符串;不加则返回人类可读描述(如"Microsoft Word 2007+") - 务必传入文件路径(
from_file),而非文件对象;若要用文件对象,得加mime=True, unbuffered=True并确保传入的是bytes(非文本流) - 遇到 PermissionError 或空文件时会抛异常,建议包在
try/except中
为什么不用 imghdr 或 filetype?
imghdr 是标准库模块,但只支持极少数图像类型(jpeg, png, gif 等),且无法识别 WebP、AVIF、HEIC 等现代格式;更严重的是它不返回 MIME,只返回简短标识符(如 "jpeg"),还得手动映射到 "image/jpeg"。
立即学习“Python免费学习笔记(深入)”;
filetype 库轻量、纯 Python,适合嵌入式或无 C 依赖场景,但签名库更新慢、误判率略高(尤其对压缩包或 Office 文档)。例如某些加密 PDF 可能被误标为 "application/zip",因为它开头含 ZIP 签名 —— 而 python-magic 会继续深入解析,避开这类陷阱。
- 需要快速判断是否为图片?
filetype够用;要生产环境做上传校验?必须用python-magic -
filetype.guess()接收bytes,适合内存中数据;python-magic默认读磁盘,若处理 BytesIO 流,得用m.from_buffer(data) - 两者都不检测文件内容逻辑合法性(如 PNG 是否真能解码),只认签名
上传场景下必须校验 MIME + 扩展名 + 内容一致性
仅靠服务端 MIME 检测仍不够安全。攻击者可构造恶意文件:比如把 PHP 代码塞进 JPEG 注释区,再改扩展名为 .jpg,此时 python-magic 仍会返回 "image/jpeg",但 Web 服务器若配置不当可能执行其中的 PHP 片段。
- 永远拒绝
application/x-php、text/x-php等可执行 MIME 类型,哪怕扩展名是.jpg - 比对客户端传来的
Content-Type、文件扩展名、python-magic结果三者是否合理共存(如.pdf→"application/pdf"OK;.pdf→"application/zip"必须拦截) - 对 Office 文档、PDF 等复杂格式,额外调用
pdfid或oletools做二次扫描(检测宏、JS、嵌入对象)
常见错误:magic.from_file 返回 "application/octet-stream"
这不是 bug,而是 libmagic 明确表示“不认识这个文件”。原因通常有三种:
- 文件太小(
- 文件是新格式(如刚发布的 AV1 视频容器),
libmagic数据库未更新 → 运行sudo file -C(Linux/macOS)更新魔数数据库,或升级python-magic - 文件被混淆/加壳/加密(如 UPX 打包的二进制),原始签名被破坏 → 此时返回
"application/octet-stream"反而是正确行为,不应强行绕过
别用后缀名 fallback 替代真实检测——那等于把门钥匙交给攻击者。


















