使用AWS S3 presigned[-post]-url上传时如何校验文件类型正确性?
S3预签名直传场景下的可靠文件类型校验方案
问题本质
两类客户端侧可拿到的文件类型标识完全不可靠,极易被攻击者篡改绕过:
- HTTP请求头携带的
Content-Type字段 - HTML文件输入组件返回的
file.type元数据
常规的真实文件类型检测逻辑,需要读取文件的Buffer或Uint8Array格式二进制内容,通过文件头魔数判断真实类型,无法仅靠元数据完成准确校验。
传统的“客户端先传文件到业务服务端校验→校验通过签发预签名地址→客户端二次传文件到S3”的流程,会导致同一个文件被传输两次,白白占用带宽,拉长上传等待时间,用户体验很差。
零重复传输的落地方案
核心思路是把校验逻辑从“上传前在业务服务端做”挪到“S3侧做”,文件只需要从客户端直传到S3一次,全程没有重复传输整文件的开销。
方案1:上传后自动触发Lambda校验(推荐,安全性最高)
- 前端体验优化(非安全依赖):客户端在上传前仅读取文件前100字节(绝大多数文件的类型魔数都存放在这段区间内,读取耗时可以忽略),在前端做初步类型拦截,减少明显不符合要求的无效上传请求。
注意:这一步完全不能作为安全校验依据,客户端的所有逻辑都可以被攻击者篡改绕过。
- 预签名策略约束:业务服务端签发
presigned-post-url时,在上传策略里增加基础约束:- 用
starts-with规则限制Content-Type必须为允许的类型前缀 - 用
content-length-range限制上传文件大小在允许的区间内 - 给上传的文件配置默认的“待校验”标签,未通过校验的文件不允许业务侧访问
- 用
- S3侧自动校验:给存储桶配置上传事件触发规则,只要有新文件上传完成,立刻触发绑定的Lambda函数:
- Lambda仅读取新上传文件的头几百字节内容,通过魔数判断文件真实类型
- 校验通过:将文件标签更新为“正常”,允许业务侧正常访问
- 校验不通过:直接删除非法文件,记录攻击日志,可根据上传者信息追加风控规则
这个方案的额外开销只有Lambda读取几百字节文件头的流量,和传输整个文件的开销比可以忽略不计。
方案2:Object Lambda访问时校验(适配存量业务)
如果存量业务不方便调整上传事件配置,可以用S3 Object Lambda做访问侧校验:
- 给存储桶配置Object Lambda接入点,所有文件访问请求都先经过Lambda处理
- 文件第一次被访问时,Lambda读取文件头做类型校验
- 校验不通过直接返回403禁止访问,同时异步删除非法文件
- 校验通过则正常返回文件内容,给文件打“已校验”标签,后续访问直接放行
这个方案改造成本更低,同样不需要客户端重复传输文件,只是校验时机从上传完成后挪到了第一次访问时。
关键避坑点
不要把预签名策略里的Content-Type匹配规则当作安全校验手段:哪怕你在签发预签名URL时指定了固定的Content-Type,攻击者依然可以构造请求篡改这个字段值,绕过策略限制上传非法文件。只有读取文件二进制内容、通过魔数判断的类型结果才是可靠的。
内容的提问来源于stack exchange,提问作者Arman
相关产品推荐
相关产品推荐

