文件上传功能怎么安全实现提示词(类型校验、大小限制、存储与访问控制、防路径穿越,防御向自查)

要实现头像上传、附件上传、批量导入这类功能,或者审查现有上传接口是否安全时用:AI 按防御清单逐项检查和实现:只信任服务端识别的文件类型、限制大小与数量、重命名并存到不可执行的位置、下载时校验权限,给出完整的接口代码。

NNathaniel bigo··原创首发·AI 辅助撰写
通用大模型 对话模型通用
你是一名注重安全的后端工程师。请帮我实现(或审查)一个文件上传功能,目标是防御常见的上传风险。本任务只用于加固自己的系统。

- 上传场景:[上传场景](例:用户上传头像、工单附件、Excel 批量导入)
- 允许的文件类型与大小:[类型与大小](例:jpg、png,最大 5MB)
- 技术栈:[技术栈](例:Node.js + Express)
- 存储位置:[存储位置](例:本地磁盘、对象存储)
- 谁能访问上传后的文件:[访问范围](例:仅上传者本人和管理员)
- 现有代码(审查时填写):
  [粘贴代码]

逐项实现或检查:
1. 大小与数量:在网关和应用两层限制请求体大小;限制单次上传的文件数;流式处理,避免把整个大文件读进内存。
2. 类型校验:
   - 用白名单而不是黑名单;
   - 不信任客户端声明的类型和文件扩展名,根据文件内容的特征识别真实类型;
   - 图片可以重新解码并重新编码,去除附带的元数据和隐藏内容;
   - 压缩包、表格、文档类文件的额外风险(如解压炸弹、宏、公式注入),以及对应的处理方式。
3. 文件名与路径:服务端生成随机文件名,不使用用户提供的文件名拼接路径;原始文件名只作为元数据保存,显示时转义;防止路径穿越。
4. 存储:存放在不会被当作脚本执行的位置,最好与应用代码分离(对象存储或独立目录);不要放在网站根目录下可以直接执行的位置。
5. 访问控制:下载时校验当前用户是否有权访问;私有文件使用短期有效的签名链接;响应时设置正确的内容类型和「作为附件下载」的头,防止在浏览器中被当作网页执行。
6. 其他:需要时对文件做病毒扫描(如 ClamAV);记录上传日志;限制上传频率;定期清理未被引用的文件。

输出:风险检查表(项目 | 当前是否满足 | 风险 | 建议)、完整的上传与下载接口代码(中文注释)、测试用例清单(例如伪造扩展名的文件、超大文件、含路径字符的文件名、越权下载)。
另外说明:前端预检查只为体验,服务端校验才算数;对象存储的桶默认设为私有,禁止列出目录。

高亮处换成你自己的内容:[上传场景]、[类型与大小]、[技术栈]、[存储位置]、[访问范围]、[粘贴代码]

ChatGPT Plus 充值

已被复制 0 次

使用说明

怎么填变量:[允许的文件类型与大小] 越严格越安全,只开放业务真正需要的类型。[谁能访问上传后的文件] 决定了是否需要签名链接和下载权限校验,用户私人附件绝不能用可以被猜到的公开地址。

常见坑:

  • 只检查文件扩展名或浏览器传来的类型字段,攻击者改个名字就能绕过。要根据文件内容识别类型。
  • 直接用用户上传的文件名保存,文件名里带上级目录符号,就可能写到预期目录之外。
  • 上传的文件可以通过固定规律的地址直接访问,任何人都能遍历下载别人的附件。

追问技巧:追问「Excel 批量导入时,如何防止单元格中的公式在别人打开导出文件时被执行」,或「改为前端直传对象存储时,服务端还需要做哪些校验」。

示例输出

示例,仅供参考(Node.js,节选)
项目当前风险建议
类型校验只检查扩展名伪造扩展名上传任意文件读取文件头识别真实类型,只允许 jpg、png
文件名使用原始文件名路径穿越、覆盖其他文件服务端生成随机文件名
访问控制公开固定地址越权下载下载接口校验归属,或使用短期签名链接
js
const ALLOWED = new Map([['image/jpeg', 'jpg'], ['image/png', 'png']])

async function saveUpload(buffer, userId) {
  const type = await fileTypeFromBuffer(buffer)             // 根据文件内容识别类型
  if (!type || !ALLOWED.has(type.mime)) throw new BadRequest('只支持 JPG、PNG 图片')
  const name = `${crypto.randomUUID()}.${ALLOWED.get(type.mime)}`   // 不使用用户提供的文件名
  const clean = await sharp(buffer).rotate().toBuffer()     // 重新编码,去除附带的元数据
  await storage.put(`avatars/${userId}/${name}`, clean, { contentType: type.mime })
  return name
}

同款作品

用这条提示词做出来的作品;原作者会因此获得积分

做同款

还没有同款,来做第一个。

Nathaniel 的更多内容

同主题

同模型

0 条评论

登录 后参与评论

还没有评论,来抢沙发~