当前位置: 首页 > news >正文

影像技术实战19:图片上传安全校验:伪装后缀、损坏图片、超大分辨率与后端防护方案

影像技术实战19:图片上传安全校验:伪装后缀、损坏图片、超大分辨率与后端防护方案

一、问题场景:图片上传功能看似简单,实际上是系统风险入口

很多业务都有图片上传:

用户头像 商品图 文章封面 评论图片 素材库 AI 训练数据上传 后台 CMS 图片

最简单的后端代码可能是:

iffilename.endswith(".jpg"):save_file(file)

这非常危险。

真实线上会遇到:

1. 后缀是 jpg,实际不是图片 2. Content-Type 是 image/jpeg,但内容是伪造的 3. 图片损坏,后续处理报错 4. 超大分辨率图片导致内存暴涨 5. SVG 内嵌脚本 6. CMYK 图片导致颜色异常 7. EXIF 方向导致展示旋转 8. 上传文件名构造路径穿越 9. 压缩炸弹拖垮服务 10. 图片解码异常阻塞请求

本文解决的问题:

如何构建一个基础可靠的图片上传校验模块,在进入影像处理流水线前拦截危险和异常文件?


二、真实问题:不要信任文件名和 Content-Type

用户上传:

avatar.jpg

不代表它真的是 JPEG。

请求头:

Content-Type: image/jpeg

也可以伪造。

后端必须基于文件内容做校验。

基本原则:

不信任文件名 不信任后缀 不信任 Content-Type 必须解码验证 必须限制大小和分辨率 必须重新编码保存

三、架构设计

推荐上传处理流程:

接收文件 ↓ 保存到临时目录 ↓ 检查文件大小 ↓ Pillow verify 校验 ↓ 重新打开读取真实格式 ↓ 检查格式白名单 ↓ 检查分辨率 ↓ 修正 EXIF ↓ 重新编码保存为安全格式 ↓ 删除临时文件

项目结构:

image-upload-secure/ ├── app.py ├── upload/ │ ├── config.py │ ├── validator.py │ ├── normalizer.py │ └── filename.py └── uploads/

四、环境准备

mkdirimage-upload-securecdimage-upload-secure python-mvenv venv pipinstallpillow==10.3.0fastapi==0.111.0uvicorn==0.30.1 python-multipart==0.0.9

五、定义上传配置

创建upload/config.py

fromdataclassesimportdataclass@dataclassclassImageUploadConfig:max_file_size_mb:int=10max_width:int=8000max_height:int=8000min_width:int=32min_height:int=32allowed_formats:tuple[str,...]=("JPEG","PNG","WEBP")

为什么要限制分辨率?

因为有些图片文件大小不大,但解码后像素巨大,会占用大量内存。


六、安全生成文件名

创建upload/filename.py

importuuiddefgenerate_safe_filename(ext:str=".jpg")->str:ifnotext.startswith("."):ext="."+extreturnf"{uuid.uuid4().hex}{ext}"

不要使用用户原始文件名:

../../app.py 头像.jpg a/b/c.jpg

这些都可能带来路径问题。


七、图片校验逻辑

创建upload/validator.py

importosfromPILimportImage,ImageOpsfromupload.configimportImageUploadConfigdefvalidate_image_file(path:str,config:ImageUploadConfig):size_bytes=os.path.getsize(path)size_mb=size_bytes/1024/1024ifsize_mb>config.max_file_size_mb:raiseValueError(f"file too large:{size_mb:.2f}MB")try:withImage.open(path)asimg:img.verify()exceptException:raiseValueError("invalid or corrupted image")withImage.open(path)asimg:img=ImageOps.exif_transpose(img)fmt=img.formatwidth,height=img.size mode=img.modeiffmtnotinconfig.allowed_formats:raiseValueError(f"unsupported image format:{fmt}")ifwidth>config.max_widthorheight>config.max_height:raiseValueError(f"image resolution too large:{width}x{height}")ifwidth<config.min_widthorheight<config.min_height:raiseValueError(f"image resolution too small:{width}x{height}")return{"format":fmt,"width":width,"height":height,"mode":mode,"size_mb":round(size_mb,4)}

注意:

img.verify()

之后需要重新Image.open(),因为 verify 会让对象进入不可继续处理的状态。


八、重新编码保存

创建upload/normalizer.py

fromPILimportImage,ImageOpsdefnormalize_to_safe_jpeg(input_path:str,output_path:str,quality:int=88,background=(255,255,255)):withImage.open(input_path)asimg:img=ImageOps.exif_transpose(img)ifimg.modein("RGBA","LA"):rgba=img.convert("RGBA")bg=Image.new("RGB",rgba.size,background)bg.paste(rgba,mask=rgba.split()[-1])img=bgelse:img=img.convert("RGB")img.save(output_path,"JPEG",quality=quality,optimize=True,progressive=True)

重新编码的好处:

统一格式 修正方向 去掉潜在异常元数据 后续处理更稳定

九、FastAPI 接入示例

创建app.py

importosimportshutilfromfastapiimportFastAPI,UploadFile,File,HTTPExceptionfromupload.configimportImageUploadConfigfromupload.validatorimportvalidate_image_filefromupload.normalizerimportnormalize_to_safe_jpegfromupload.filenameimportgenerate_safe_filename app=FastAPI()config=ImageUploadConfig()TEMP_DIR="tmp"UPLOAD_DIR="uploads"os.makedirs(TEMP_DIR,exist_ok=True)os.makedirs(UPLOAD_DIR,exist_ok=True)@app.post("/upload-image")asyncdefupload_image(file:UploadFile=File(...)):temp_name=generate_safe_filename(".tmp")temp_path=os.path.join(TEMP_DIR,temp_name)withopen(temp_path,"wb")asf:shutil.copyfileobj(file.file,f)try:info=validate_image_file(temp_path,config)output_name=generate_safe_filename(".jpg")output_path=os.path.join(UPLOAD_DIR,output_name)normalize_to_safe_jpeg(temp_path,output_path)return{"status":"ok","image":output_name,"info":info}exceptExceptionase:raiseHTTPException(status_code=400,detail=str(e))finally:ifos.path.exists(temp_path):os.remove(temp_path)

运行:

uvicorn app:app--reload

十、验证上传接口

用 curl 测试:

curl-XPOST"http://127.0.0.1:8000/upload-image"\-F"file=@test.jpg"

正常返回:

{"status":"ok","image":"xxxx.jpg","info":{"format":"JPEG","width":1920,"height":1080}}

十一、踩坑记录

坑 1:只检查后缀

这是最常见的错误。

坑 2:只检查 Content-Type

Content-Type 是客户端传的,不能信。

坑 3:允许 SVG 直接上传展示

SVG 可能包含脚本。除非做严格清洗,否则不要当普通图片开放上传。

坑 4:不限制分辨率

超大分辨率图片可能导致内存暴涨。

坑 5:保存原文件名

可能引起路径穿越、覆盖文件、编码异常等问题。


十二、适合收藏:图片上传校验清单

1. 保存到临时目录 2. 限制文件大小 3. 不信任后缀 4. 不信任 Content-Type 5. Pillow verify 解码校验 6. 检查真实格式 7. 检查分辨率上下限 8. 修正 EXIF 方向 9. 重新编码保存 10. 使用 UUID 文件名 11. 删除临时文件 12. 记录失败原因

十三、避坑清单

1. 不要直接保存原始上传文件用于展示 2. 不要使用用户文件名 3. 不要允许任意格式 4. 不要忽略超大分辨率 5. 不要只检查文件大小 6. 不要忽略损坏图片 7. 不要忘记清理临时文件 8. 不要随便允许 SVG

十四、总结与优化建议

图片上传是影像系统的入口,入口不安全,后面所有处理都会不稳定。

工程建议:

上传文件先临时保存 内容校验通过后再入库 统一格式重新编码 限制大小和分辨率 安全文件名 失败原因可追踪

后续优化:

1. 接入对象存储直传 2. 上传后异步生成缩略图 3. 增加图片内容审核 4. 增加病毒扫描 5. 增加用户上传频率限制 6. 增加图片质量检测

图片上传不是简单的 save file,而是影像系统最重要的安全边界之一。

http://www.jsqmd.com/news/849133/

相关文章:

  • 黄仁勋夫妇基金会捐赠 1.08 亿美元算力,助力科研机构 AI 研究
  • 人脸识别:用数据蒸馏训练高精度人脸识别模型
  • OpenClaw 用户配置 Taotoken 作为 Provider 的详细操作指南
  • 临床决策倒计时:Perplexity医生信息搜索如何将循证检索从15分钟压缩至22秒?
  • 从沙子到车辙(1.2):计算的梦想与破灭
  • 从Memos到Obsidian:利用Thino插件实现数据无缝迁移
  • 不锈钢发酵罐厂家/不锈钢配液罐厂家/不锈钢搅拌罐厂家/不锈钢调配罐定制厂家推荐:海之鑫领衔,2026行业实力厂家深度盘点 - 栗子测评
  • C++(随机数练习题)
  • 022、旋转变压器原理与解码
  • C语言嵌入式开发中的软件复位实现方法
  • 蓝桥杯C++选手必看:动态规划从入门到拿分,我用这5道题搞定了(附完整代码)
  • 03手把手学会yolov8模型之使用Labelimg标注数据集
  • AI数据标注实战:如何高效、准确地标注训练数据
  • Java SE 11 与 Spring Boot 在电商场景中的应用
  • 【更新至2024年】2011-2024年地级市金融科技指数数据
  • Proteus仿真避坑指南:数字电子钟的24小时清零与闹钟功能实现
  • vue多语言交易所系统/期货/合约交易/质押生息/盲盒/挖矿/跟单源码
  • Gdev 至 Rust 移植工程(七)
  • GIS技巧100例23-ArcGIS像元统计实战:从月度栅格到年度气候指标
  • 别再为Keil 5报错头疼了!STM32F401CCU6固件库移植保姆级避坑指南(V1.8.0)
  • AI产品经理入门实战:如何理解意图识别?
  • AArch64架构Watchpoint机制详解与调试实践
  • 如何3步掌握Path of Building物品制作:终极实战指南
  • 通过Taotoken用量看板分析团队大模型API消耗模式与优化点
  • 2026年选对工作钢格板厂家,这三大核心标准决定你的采购成败
  • 【RuoYi】数据分页功能分析 —— 以登录日志页面为例
  • 【原创】智询管理系统操作说明
  • Spring Boot 3.0升级踩坑记:手把手教你解决 ‘javax.servlet.http不存在‘ 的报错
  • 技术动态 | 大模型驱动情报领域知识图谱构建新范式:ERC-KG方法精确率高达94.32% - 解放军网络空间部队信工大等
  • 无人机精准着陆:NMPC-CBF技术实现厘米级控制