溯仑智算
溯仑智算 SU.RUN开发者文档
获取接入支持
溯仑智算
溯仑智算 SU.RUN
开发者文档
开始使用
文档中心
阅读路径、接入顺序与专题总览
存储接入快速开始
第一次接入时优先阅读
存储接入总览
能力边界、使用路径与整体说明
本地配置与验证指南
在本地完成示例接口与最小验证
上传与下载
授权上传指南
浏览器、App 与客户端上传方式
授权下载指南
受控下载、权限判断与短时授权
前端直传安全规范
长期密钥保护与权限边界
大文件上传实战
大文件上传、重试与断点续传
规划与治理
文件路径命名规范
存储桶、路径、目录与归档规则
自定义域名接入
品牌化访问、证书与上线准备
接口说明
服务端接入方式、鉴权边界与返回结构
最小后端接入示例
上传下载授权与确认入库的完整串联
代码示例
JavaScript、Python 与 Go 接入示例
AI 与工作流
AI 环境接入说明
常见 AI 环境的接入说明
AI 训练数据与结果回写规范
模型、数据集、日志与输出治理
排障与帮助
错误码与问题排查
常见异常定位与恢复建议
接入常见问题总览
按角色整理的常见问题说明
支持中心
获取接入支持
获取接入支持
开始使用
文档中心存储接入快速开始存储接入总览本地配置与验证指南
上传与下载
授权上传指南授权下载指南前端直传安全规范大文件上传实战
规划与治理
文件路径命名规范自定义域名接入接口说明最小后端接入示例代码示例
AI 与工作流
AI 环境接入说明AI 训练数据与结果回写规范
排障与帮助
错误码与问题排查接入常见问题总览
当前文档
长期密钥保护与权限边界
文档中心

前端直传安全规范

前端直传可以使用,但需要放在清晰的权限边界内,重点保护长期密钥、关键路径和业务访问控制。

安全咨询
support@su.run

浏览器上传 / App 上传 / 长期密钥边界

长期密钥一旦进入前端,就不再可控

浏览器代码、移动端包体、小程序脚本都运行在用户环境中。只要长期密钥进入这些环境,就意味着它可能被抓包、反编译、复制或复用,后续任何文件读写都很难真正收口。

关键对象路径不能交给客户端自行决定

文件路径本质上就是业务资源路径。把它完全交给客户端,相当于把关键目录写权限部分外放。正式系统里,关键路径应由业务后端根据组织、项目、用户和业务类型统一生成。

上传成功不代表业务完成

很多团队会把浏览器上传成功误认为业务完成,但正式流程还需要做文件确认、业务记录绑定、审计日志和后续下载授权,否则后面会出现“文件已上传,但系统里没有记录”的问题。

常见错误做法

  • 把长期密钥直接写进前端代码或移动端包体。
  • 让前端自己决定 bucket 和 objectKey。
  • 上传成功后不回调业务后端,导致文件与业务记录脱节。
  • 上传授权或下载授权有效期过长。

建议安全流程

  • 前端上传前先请求业务后端接口。
  • 由后端生成 objectKey,并签发短时 uploadUrl。
  • 上传成功后把 objectKey 回传后端入库。
  • 下载同样由后端生成短时授权,而不是直接暴露长期访问能力。

建议架构

  • 客户端只采集文件与显示进度,不保存长期访问密钥。
  • 业务后端负责鉴权、文件路径生成、上传授权签发、日志记录和上传完成确认。
  • 存储服务只承担文件读写,不直接暴露业务权限决策。
  • 高敏感文件下载同样走后端短期授权,不做永久直链分发。

后端签名接口示例

推荐由业务后端统一生成文件路径并签发上传授权。这样目录、权限和有效期都能被后端掌控。

export async function POST(request: Request) {
  const body = await request.json();
  const currentUser = await requireCurrentUser();

  const objectKey = [
    'uploads',
    currentUser.organizationId,
    new Date().toISOString().slice(0, 10),
    String(Date.now()) + '-' + body.fileName,
  ].join('/');

  const uploadUrl = await createUploadUrl({
    bucket: 'media-assets',
    objectKey,
    contentType: body.contentType,
    expiresIn: 600,
  });

  return Response.json({
    success: true,
    bucket: 'media-assets',
    objectKey,
    uploadUrl,
    expiresIn: 600,
    requestId: crypto.randomUUID(),
  });
}

浏览器上传流程示例

浏览器只负责申请授权、上传文件和回传 objectKey,不直接碰长期凭证。

async function uploadAsset(file: File) {
  const authResponse = await fetch('/api/storage/presign-upload', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      fileName: file.name,
      contentType: file.type,
    }),
  });

  const { uploadUrl, objectKey } = await authResponse.json();

  await fetch(uploadUrl, {
    method: 'PUT',
    headers: {
      'Content-Type': file.type,
    },
    body: file,
  });

  await fetch('/api/assets/confirm-upload', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ objectKey }),
  });
}
SECURITY NOTICE

必须守住的边界

  • 浏览器和 App 不保存长期访问密钥。
  • bucket 和 objectKey 由后端控制。
  • 上传和下载都使用短期授权。
  • 关键操作建议记录 requestId 和审计信息。

建议保留的审计字段

  • 谁申请了上传授权,来自哪个组织或项目。
  • 签发给了哪个 bucket 和 objectKey。
  • 授权何时签发、何时过期。
  • 最终哪个 objectKey 被业务系统确认入库。
  • 是否出现重复上传、覆盖写入或异常下载行为。

上线检查清单

  • 前端仓库、移动端代码和配置里没有长期密钥。
  • 对象路径由后端统一生成,不由客户端自由拼接。
  • 上传授权有明确有效期,并限制目录和文件类型。
  • 上传成功后存在确认入库动作,而不只是浏览器显示成功。
  • 关键上传和下载行为能通过 requestId 与日志串联。

接入常见问题

前端是否完全不能使用 SDK?

不是完全不能,而是不能直接持有长期密钥。前端可以使用短期 uploadUrl 或 downloadUrl,也可以消费业务 API,但长期权限必须由后端承接。

为什么一直强调 confirm-upload?

因为对象写入成功只说明文件存在了,不说明业务系统已经认领它。正式系统里,文件和业务记录必须在后端再完成一次绑定。

如果只是内部后台使用,是否仍需保持同样边界?

建议仍然保持同样边界。内部后台一旦做大、接入更多人员和环境,没有统一的签名与审计边界会很快失控。

上一篇
授权下载指南
受控下载、权限判断与短时授权
下一篇
大文件上传实战
大文件上传、重试与断点续传
更多帮助

你可能还需要这些帮助入口

文档中心帮助你完成接入,客户服务页帮助你了解采购、支持与服务信息。

邮件支持

需要迁移协助或接入支持时,可以直接进入邮件支持入口。

进入支持中心

客户常见问题

采购、测试申请、迁移安排与售后问题,可先查看这份常见问题说明。

查看常见问题

价格与采购说明

需要确认容量区间、采购方式、续费与对账说明时,可从这里继续查看。

查看价格说明