feat: 实现 SSRF 安全 HTTP、密钥加密与本地存储 #8

Closed
opened 2026-08-20 18:01:01 +08:00 by ila · 0 comments
Owner

基本信息

  • 类型:需求
  • 所属 Epic:#3
  • 所属 MVP / 版本:#4(MVP-0)
  • 阶段:已完成

依赖与并行

  • 前置工单:#6、#7
  • 是否允许与前置工单并行:否
  • 原因:依赖项定义本工单所需的可执行环境、共享模型、接口或已确认设计;未满足时保持待实施,不标记阻塞。

子项目影响

  • 仅影响的子项目 / 交付单元:internal/platform;以及 internal/core/storage 的最小元数据接口扩展
  • 是否跨子项目:是;为满足已确认的用户归属元数据,storage 接口需要携带 owner_id/generation_id
  • 是否修改共享接口或契约:是;实现 core 的 HTTP、crypto 和 storage 接口
  • 各子项目需要执行的验证:见“验证方式”和验收标准。

原始需求

  • 来源:用户对话;Product-Requirements-Overview、Architecture-and-Code-Map、Business-Rules-and-Glossary
  • 提出时间:2026-08-20
  • 关键原话或脱敏摘要:用户要求“为 MVP-0 的生产实现拆分单元工单”;本工单负责 实现 SSRF 安全 HTTP、AES-GCM 密钥信封和受保护本地存储。

要解决什么

MVP-0 的上游访问、密钥和生成物属于高风险边界,必须在业务调用前提供可复用、默认安全且有专项测试的平台适配器。

做什么 / 不做什么

做

  • 实现 DNS 解析后、连接前校验的 DialContext,拒绝回环、私网、链路本地、组播和未指定 IPv4/IPv6。
  • 禁止环境代理绕过;每次 redirect 和上游结果 URL 下载重新验证目标并限制次数、scheme 和端口。
  • 实现带 version/key_id/nonce/ciphertext 的 AES-GCM 信封、key ring 解密和轮换兼容。
  • 实现受保护本地存储:临时文件、同文件系统原子 rename、用户归属元数据、图片解码和 256px 缩略图。
  • 对输入/下载设置字节数、MIME、实际格式、像素和超时配置门禁。

不做

  • 不关闭或提供绕过 SSRF 的调试开关,不允许任意代理。
  • 不记录、响应或持久化明文 API Key 和主密钥。
  • 不实现 Provider 协议、用户 handler、公开静态目录、S3/OSS 或清理任务。

已确认方案

  • 所有出站连接统一经过安全 Transport;业务代码不能自行创建绕过它的 http.Client。
  • 密钥主材料只从环境/key ring 注入,密文可区分 key_id 并支持先写新密钥再退役旧密钥。
  • 文件只有在完整校验后原子落位;失败清理本次临时文件,不删除其他任务文件。

预计修改文件:

  • internal/platform/http/
  • internal/platform/crypto/
  • internal/platform/storage/
  • 对应专项与集成测试

需求变化记录

  • 2026-08-20:实施前复核发现 #7 的 storage.Store 只接收 key/content,不能表达 #8 已确认的用户归属元数据。将其最小扩展为结构化 PutRequest/Object 元数据;变更仅涉及 core 接口,不改变迁移、页面或产品范围。实现中若范围、接口、数据、依赖、验收或风险发生变化,必须先更新本工单;改变已确认结果时重新等待用户确认。

设计与原型门禁

  • 修改类型:非 UI
  • 所需设计证据:已确认的架构、数据、安全或流程设计;不要求 UI 原型
  • 事实来源:核心 Wiki 与父工单 #4
  • 状态:已确认;具体实现差异仍须按工单变化规则处理
  • 无需 UI 原型原因:本工单不改变用户界面

文档影响

  • 不影响长期文档
  • 按实际变化更新 Project-Profile、Architecture-and-Code-Map、Local-Development-and-Verification、Deployment-and-Operations 或 Business-Rules-and-Glossary
  • Wiki 先改、在线回读后再同步 docs/,不得直接维护镜像

交付文档影响

  • 无交付文档影响,原因:内部实现任务;若实际改变部署、配置或支持方式,执行前更新本项
  • 更新已有交付文档
  • 新增交付文档

验收标准

  • IPv4/IPv6 私网、DNS 重解析、redirect、proxy、恶意结果 URL 用例均被拒绝。
  • 允许的公网目标在 mock DNS/连接环境中可访问,超时和大小限制生效。
  • AES-GCM 往返、篡改失败、未知 key_id、轮换兼容测试通过,日志/错误无明文。
  • 文件原子落位、失败清理、图片解码限制和 256px 缩略图测试通过。
  • 仓库扫描无明文密钥样例和绕过安全 Client 的生产调用。

验证方式

  • go test ./internal/platform/...
  • go test -race ./internal/platform/...
  • SSRF 表驱动/自定义 Resolver 与 Dialer 测试
  • 密钥轮换和篡改测试
  • 存储临时目录、原子 rename、图片炸弹边界测试

未执行或因环境不足无法执行的验证必须如实回写,不得把预期结果记为通过。

风险和回退

  • 高风险:SSRF 绕过和密钥泄露;发现任何未覆盖路径必须停止实施并更新工单。
  • 风险:Windows 与 Linux 原子文件语义不同;测试两类边界,无法验证的平台如实记录。
  • 回退:回退平台适配器提交并停止上游联调;不得以关闭校验作为临时回退。

实施与验证证据(2026-08-20)

  • HTTP:scheme/port、IPv4/IPv6 特殊地址、DNS 重绑定、redirect、环境代理、恶意结果 URL、超时和字节限制均有 mock 测试;底层错误不回显 URL 查询参数。
  • Crypto:AES-GCM version/key_id/nonce/ciphertext 信封,AAD 绑定元数据;往返、篡改、未知 key、旧/新 key 轮换通过。
  • Storage:同目录 content+metadata 原子 rename,owner_id/generation_id 明确持久化;路径越界/符号链接、失败清理、MIME/格式/像素和 256px 缩略图通过。
  • 验证:platform test/race、全项目 build/vet/test、不安全 HTTP 扫描、core 依赖扫描、Harness、42 项 Python 测试和 Wiki 一致性均通过。
  • 未验证:Linux 实机原子 rename 语义留待部署/CI;未调用真实上游。
  • Architecture Wiki revision:97f301d12a81b734a80c90b77feaed79373248c1。
  • 任务归档 revision:6bae5dbf5e095ac09984a3fed024ff1c1a05af6e。
  • 提交:ceac63163895cf06abce5702cd6b0787c677e6ff、94468c5c44fe434d6a3972548e34ddcf1666b92a,均已推送。

当前状态:待用户验收,不关闭。#9 可顺序继续。

验收结论

  • 用户于 2026-08-21 明确确认 #8 验收通过。
  • MVP-0 单元验收文档提交:919e11f,已推送到 main。
  • 任务归档 revision:be995ae6015a。
## 基本信息 - 类型:需求 - 所属 Epic:#3 - 所属 MVP / 版本:#4(MVP-0) - 阶段:已完成 ## 依赖与并行 - 前置工单:#6、#7 - 是否允许与前置工单并行:否 - 原因:依赖项定义本工单所需的可执行环境、共享模型、接口或已确认设计;未满足时保持待实施,不标记阻塞。 ## 子项目影响 - 仅影响的子项目 / 交付单元:internal/platform;以及 internal/core/storage 的最小元数据接口扩展 - 是否跨子项目:是;为满足已确认的用户归属元数据,storage 接口需要携带 owner_id/generation_id - 是否修改共享接口或契约:是;实现 core 的 HTTP、crypto 和 storage 接口 - 各子项目需要执行的验证:见“验证方式”和验收标准。 ## 原始需求 - 来源:用户对话;Product-Requirements-Overview、Architecture-and-Code-Map、Business-Rules-and-Glossary - 提出时间:2026-08-20 - 关键原话或脱敏摘要:用户要求“为 MVP-0 的生产实现拆分单元工单”;本工单负责 实现 SSRF 安全 HTTP、AES-GCM 密钥信封和受保护本地存储。 ## 要解决什么 MVP-0 的上游访问、密钥和生成物属于高风险边界,必须在业务调用前提供可复用、默认安全且有专项测试的平台适配器。 ## 做什么 / 不做什么 ### 做 - 实现 DNS 解析后、连接前校验的 `DialContext`,拒绝回环、私网、链路本地、组播和未指定 IPv4/IPv6。 - 禁止环境代理绕过;每次 redirect 和上游结果 URL 下载重新验证目标并限制次数、scheme 和端口。 - 实现带 version/key_id/nonce/ciphertext 的 AES-GCM 信封、key ring 解密和轮换兼容。 - 实现受保护本地存储:临时文件、同文件系统原子 rename、用户归属元数据、图片解码和 256px 缩略图。 - 对输入/下载设置字节数、MIME、实际格式、像素和超时配置门禁。 ### 不做 - 不关闭或提供绕过 SSRF 的调试开关,不允许任意代理。 - 不记录、响应或持久化明文 API Key 和主密钥。 - 不实现 Provider 协议、用户 handler、公开静态目录、S3/OSS 或清理任务。 ## 已确认方案 - 所有出站连接统一经过安全 Transport;业务代码不能自行创建绕过它的 `http.Client`。 - 密钥主材料只从环境/key ring 注入,密文可区分 key_id 并支持先写新密钥再退役旧密钥。 - 文件只有在完整校验后原子落位;失败清理本次临时文件,不删除其他任务文件。 预计修改文件: - `internal/platform/http/` - `internal/platform/crypto/` - `internal/platform/storage/` - 对应专项与集成测试 ## 需求变化记录 - 2026-08-20:实施前复核发现 #7 的 `storage.Store` 只接收 key/content,不能表达 #8 已确认的用户归属元数据。将其最小扩展为结构化 PutRequest/Object 元数据;变更仅涉及 core 接口,不改变迁移、页面或产品范围。实现中若范围、接口、数据、依赖、验收或风险发生变化,必须先更新本工单;改变已确认结果时重新等待用户确认。 ## 设计与原型门禁 - 修改类型:非 UI - 所需设计证据:已确认的架构、数据、安全或流程设计;不要求 UI 原型 - 事实来源:核心 Wiki 与父工单 #4 - 状态:已确认;具体实现差异仍须按工单变化规则处理 - 无需 UI 原型原因:本工单不改变用户界面 ## 文档影响 - [ ] 不影响长期文档 - [x] 按实际变化更新 Project-Profile、Architecture-and-Code-Map、Local-Development-and-Verification、Deployment-and-Operations 或 Business-Rules-and-Glossary - Wiki 先改、在线回读后再同步 `docs/`,不得直接维护镜像 ## 交付文档影响 - [x] 无交付文档影响,原因:内部实现任务;若实际改变部署、配置或支持方式,执行前更新本项 - [ ] 更新已有交付文档 - [ ] 新增交付文档 ## 验收标准 - [x] IPv4/IPv6 私网、DNS 重解析、redirect、proxy、恶意结果 URL 用例均被拒绝。 - [x] 允许的公网目标在 mock DNS/连接环境中可访问,超时和大小限制生效。 - [x] AES-GCM 往返、篡改失败、未知 key_id、轮换兼容测试通过,日志/错误无明文。 - [x] 文件原子落位、失败清理、图片解码限制和 256px 缩略图测试通过。 - [x] 仓库扫描无明文密钥样例和绕过安全 Client 的生产调用。 ## 验证方式 - `go test ./internal/platform/...` - `go test -race ./internal/platform/...` - SSRF 表驱动/自定义 Resolver 与 Dialer 测试 - 密钥轮换和篡改测试 - 存储临时目录、原子 rename、图片炸弹边界测试 未执行或因环境不足无法执行的验证必须如实回写,不得把预期结果记为通过。 ## 风险和回退 - 高风险:SSRF 绕过和密钥泄露;发现任何未覆盖路径必须停止实施并更新工单。 - 风险:Windows 与 Linux 原子文件语义不同;测试两类边界,无法验证的平台如实记录。 - 回退:回退平台适配器提交并停止上游联调;不得以关闭校验作为临时回退。 ## 实施与验证证据(2026-08-20) - HTTP:scheme/port、IPv4/IPv6 特殊地址、DNS 重绑定、redirect、环境代理、恶意结果 URL、超时和字节限制均有 mock 测试;底层错误不回显 URL 查询参数。 - Crypto:AES-GCM version/key_id/nonce/ciphertext 信封,AAD 绑定元数据;往返、篡改、未知 key、旧/新 key 轮换通过。 - Storage:同目录 content+metadata 原子 rename,owner_id/generation_id 明确持久化;路径越界/符号链接、失败清理、MIME/格式/像素和 256px 缩略图通过。 - 验证:platform test/race、全项目 build/vet/test、不安全 HTTP 扫描、core 依赖扫描、Harness、42 项 Python 测试和 Wiki 一致性均通过。 - 未验证:Linux 实机原子 rename 语义留待部署/CI;未调用真实上游。 - Architecture Wiki revision:`97f301d12a81b734a80c90b77feaed79373248c1`。 - 任务归档 revision:`6bae5dbf5e095ac09984a3fed024ff1c1a05af6e`。 - 提交:`ceac63163895cf06abce5702cd6b0787c677e6ff`、`94468c5c44fe434d6a3972548e34ddcf1666b92a`,均已推送。 当前状态:待用户验收,不关闭。#9 可顺序继续。 ## 验收结论 - 用户于 2026-08-21 明确确认 #8 验收通过。 - MVP-0 单元验收文档提交:`919e11f`,已推送到 `main`。 - 任务归档 revision:`be995ae6015a`。
ila closed this issue 2026-08-21 11:59:12 +08:00
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: OPC/chorus#8