Files
fire-safety-ymd/docs/project/security-access-control-boundary.md
2026-09-05 17:36:23 +08:00

13 KiB
Raw Blame History

安全与访问控制边界

项 内容
项目 fire-safety-ymd
状态 SuperAgent 出站、用户对话 API v1 与空间只读 MCP 代码控制已实现;真实环境、最终用户授权和持久审计待完成
最近更新 2026-09-05

1. 目的

本文定义用户侧应用、Go 服务、SuperAgent、MCP 工具和 PostgreSQL/PostGIS 之间的信任边界。当前已实现服务间 MCP 基线控制,但不代表最终用户鉴权、实库 readiness、生产网络或持久审计已经完成。

2. 当前实现状态

能力 状态 当前含义
GET /health 已实现 公开的进程存活响应,不访问业务数据
用户认证 仅首版联调门禁 /api/chat 使用独立静态 Bearer;可选兼容路径用同一信任方向的 xtoken;默认要求至少 32 个可打印 ASCII 字符;已交付旧短凭证仅可通过默认关闭的显式 legacy 开关在受控测试/迁移窗口暂时兼容;它们不是最终用户身份,身份提供方和正式 Token 格式待确认
角色/区域/租户授权 部分实现 MCP 使用显式服务端静态范围:默认镇街白名单,或经授权的数据库全范围;最终用户动态身份/角色/租户仍未实现
SuperAgent Open API Adapter 已实现、模拟测试通过 默认关闭;Secret 仅由项目环境变量注入;真实环境未联调
用户聊天与会话映射 已实现、默认关闭 原生 POST /api/chat 和可选 DashScope 风格 completion 路径、严格 SSE 最终回答、单进程内存映射和同会话并发冲突;无持久化、跨实例恢复或最终用户授权
MCP 工具 已实现、默认关闭 7 个固定只读工具(含地名候选搜索);独立 Bearer、body/Origin/schema/半径/数量/超时控制;实库严格 readiness 和本地真实工具查询已通过,公网/SuperAgent 待联调
PostgreSQL/PostGIS SRID 严格 readiness 已通过 pgxpool、连接级默认只读、固定参数化 SQL;4,048 条非空几何已补齐 SRID 4326,35 条无效几何继续排除并告警
测试环境容器/公网入口 配置基线已建立、目标机待验证 单实例非 root 容器,只发布宿主机回环端口;Nginx 终止 TLS 并只公开精确路径;运行时不接收迁移凭证
审计存储 未实现 事件、字段和保留周期待确认

3. 信任区域

区域 信任判断 主要控制
用户输入 不可信 身份认证、大小限制、格式校验、提示注入隔离
Chat 静态 Bearer 仅受控联调可信 独立 Secret、精确 CORS Origin、默认关闭;不能充当用户身份或字段级授权
Go 服务端身份上下文 授权事实的唯一入口 Token 验证、角色与区域解析、不可被模型覆盖
SuperAgent 输入与输出 外部、非权威 最少数据、超时、输出约束、工具侧重新授权
MCP 参数 不可信,即使由 Agent 生成 schema 校验、范围上限、服务端注入授权上下文
Repository 查询 受控代码 参数化 SQL、白名单、只读角色、超时和行数上限
PostgreSQL/PostGIS 业务事实来源但可能陈旧或不完整 权限、数据质量、来源与更新时间标记
日志与审计 受限数据面 脱敏、访问控制、保留和完整性策略

4. 身份与授权原则

  • 客户端提交的 user_id、角色、区域或租户声明不能直接作为授权依据。
  • 首版 /api/chat DTO 根本不接受 user_id、external_subject_id、角色、区域、Provider Session 或 metadata;服务端固定测试主体不能用于用户级授权。
  • Go 服务从经过验证的凭证中建立可信身份上下文,并将授权范围与请求生命周期绑定。
  • SuperAgent 不做最终授权;每次 MCP 调用都在服务端重新校验工具权限和数据范围。
  • 模型可提供地点、半径、资源类型等业务查询条件,但不能自由指定要冒充的用户、租户或权限。
  • 默认拒绝;新增工具、字段或数据表必须进入显式权限矩阵。
  • 联系人、电话和精确敏感位置按字段级权限控制,不因同一记录的普通字段可见而自动可见。
  • FIRE_SAFETY_MCP_SCOPE_MODE=all 是 MCP 固定查询表的数据库全范围授权,只能在该 MCP 凭证确实获准读取这些表全部记录时显式使用;它不会从业务数据自动推导授权。
  • all 与镇街白名单不能同时配置,避免操作者误以为白名单仍限制结果;两种模式都不能由模型或工具参数修改。
  • FIRE_SAFETY_CHAT_ALLOW_LEGACY_SHORT_TOKEN 默认必须为 false。只有已交付旧客户端的 Chat 凭证较短且无法立即更换时,才允许在受控测试/迁移窗口显式设为 true;无论开关如何,Chat 凭证必须非空、不超过 4096 字节且仅含 ASCII 0x21-0x7e(不得包含空格、控制字符或 Unicode)。该开关只影响 Chat 原生 Bearer 和兼容入口 xtoken,不放宽 MCP Token 至少 32 个可打印 ASCII 字符的要求;Chat、SuperAgent Open API 和 MCP 三种凭证必须不同。轮换完成后必须恢复 false,新环境不得开启。启用期间仅记录不含 Secret 的安全 warning,以提示后续清理。
  • 地名搜索只读取已允许的名称、镇街、村庄和几何字段,仍应用相同服务端数据范围;不读取联系人、电话或任意表。
  • 地名匹配输出属于候选。线和面的代表点只用于帮助用户识别记录,未经用户确认不得作为演练点继续查询或形成距离结论。

5. MCP 工具边界

MCP 第一阶段已按以下只读边界实现:

  • 工具对应稳定领域能力,不提供 execute_sql、任意表查询、文件读取或通用 HTTP 代理。
  • JSON schema 限制字符串长度、枚举、坐标范围、半径、分页和最大结果数。
  • Repository 只访问允许的 schema、表和字段,动态标识符来自代码白名单。
  • 输出只包含回答所需字段,并表达数据来源、更新时间、状态和不确定性。
  • 权限不足与“没有数据”使用不同稳定状态,避免 Agent 猜测。
  • 调用记录至少关联 request ID、可信主体、工具名、授权范围、耗时、结果类别和数据源版本;审计日志不保存无必要的完整敏感正文。

当前日志已记录 request ID、操作、耗时和结果类别;可信主体、数据源版本和持久审计尚未实现,因此生产前仍需补齐。

任何写工具、资源调度或状态变更都需要新的 Spec、幂等设计、人工确认边界、审计和安全 Review,不属于默认扩展。

6. PostgreSQL/PostGIS 边界

  • 应用数据库角色使用最小权限;MCP 查询角色默认只授予必要表或视图的 SELECT。
  • 数据迁移凭证与运行时只读凭证分离;2026-09-05 的一次性 SRID 迁移使用表所有者执行,完成后不应保留在应用部署环境。
  • Compose 从未提交的 .env 注入运行时配置,但会把 FIRE_SAFETY_POSTGIS_MIGRATION_DSN 强制覆盖为空;镜像构建不得复制 .env、证书、SQL 导出或 Excel 数据。
  • 应用容器内监听 8080,只发布宿主机 127.0.0.1:16587,公网只经 Nginx 的 HTTPS 精确路径进入;16587、容器 8080 和数据库端口不得加入公网安全组。
  • 使用参数化查询,不把用户或模型内容拼入 SQL、表名、排序或空间表达式。
  • 设置连接、查询和 statement timeout;限制半径、结果数和空间复杂度,防止昂贵查询。
  • 优先通过项目领域视图或明确映射屏蔽历史物理表名和不一致字段。
  • 验证 extension、SRID、几何类型、有效性、索引和单位后才开放空间结论。当前无效几何不参与结论:原始记录保留,readiness 告警,固定查询使用 ST_IsValid 排除,工具响应声明结果可能不完整。
  • 原始 SQL 中的 DROP TABLE、owner、sequence 和 extension 操作必须在隔离环境审计,不对现有数据库直接执行。
  • 数据库错误对外映射为稳定错误类别,不返回 DSN、SQL 文本、schema 细节或堆栈。

7. SuperAgent 数据边界

  • 只发送完成当前请求所需的最少上下文,不默认发送联系人、电话、完整数据库记录或长期会话历史。
  • SuperAgent 凭证仅保存在服务端 Secret,按环境隔离并支持轮换。
  • Open API Key 不得复用 TH Hotel 或其他项目凭证;本项目只读取 FIRE_SAFETY_SUPERAGENT_OPEN_API_KEY。
  • Provider 的 Content-Location 必须与配置 Base URL 同源;客户端禁止跟随重定向,避免跨域转发 Authorization。
  • SSE 只有在最终内容、成功 run.completed 和顶层 end 同时存在时成功;断流恢复不得重发原消息。
  • 公开 Trace 投影不包含原始工具输入、输出、Header、Cookie 或 Provider 原始 payload。
  • 明确平台的数据留存、训练使用、区域、子处理方和删除能力后,才能发送受限数据。
  • 流式事件和工具调用都按不可信外部数据解析,设置消息大小、事件类型和状态机约束。
  • 上游答案返回用户前应保留安全提示、数据时间和工具错误状态,不能把模型文本升级为权威事实。
  • /api/chat 不转发消息 delta;只有 Adapter 的严格成功条件全部满足后才发送最终 message 和 done。公开进度只保留安全的 run.* / tool.* 事件、工具名和状态。
  • 兼容 completion 路径同样不转发消息 delta;它先返回无正文的 finish_reason="null",严格成功后才发送 finish_reason="stop" 和最终正文。URL App ID 只是公开路由标识,不是授权依据。
  • 兼容路径的 xtoken 复用 Chat 入站凭证而不是 SuperAgent Key。Nginx 不保存、比较或注入任何应用 Secret,只把 Header 交给 Go 校验。
  • FIRE_SAFETY_CHAT_ALLOW_LEGACY_SHORT_TOKEN 是 Go 服务侧的配置,不由 Nginx 参与;Nginx 不读取、比较或存储 Chat Token,短凭证兼容规则和 warning 均由 Go 执行。
  • 同一内存会话只允许一个活动 Run。流失败或结果不确定时删除本地映射,避免继续复用可能仍在运行的 Provider Session。
  • 当前会话只在单进程内存中保存且有数量/TTL 上限;不保存消息历史。重启或多实例切换会导致旧对话不可用,不得向用户承诺持久会话。

8. 敏感数据与日志

至少按以下类别处理:

数据 基线分类 日志策略
API Key、Token、Cookie、数据库密码 Secret 禁止记录
联系人、电话、用户标识 个人/受限 默认脱敏,不记录完整值
精确设施或风险区域坐标 业务敏感 按权限最少披露,不记录完整结果集
用户问题和对话 可能含敏感信息 默认不记录原文,使用摘要或分类字段
工具名、耗时、结果类别 运行元数据 可记录,不附敏感 payload

生产前需确定数据分类负责人、日志访问角色、保留周期、删除流程和安全事件响应方式。

当前 Chat 日志只记录 request ID、结果类别、是否复用和耗时,不记录消息、回答、对话 ID、Provider Session 或 Trace payload。docs/import/db-samples/*.sql 含真实联系人、电话和精确坐标,仅作为本地只读输入并由 Git 忽略;不得执行或进入版本历史。长期测试数据必须另做脱敏 fixture。

9. 应急场景安全

  • 系统只提供辅助信息,不替代报警、撤离和现场指挥。
  • 数据缺失、陈旧、无状态或工具失败时必须显式说明,不能生成看似确定的资源可用结论。
  • 涉及路线、危险源或处置禁忌的功能需要专门规则、权威来源、版本和测试,不仅依赖模型提示词。
  • 任何可能延误报警或撤离的交互流程都必须在实现前进行安全审查。

10. 待确认决策

  • 身份提供方、Token 验证方式和服务间认证。
  • /api/chat 与兼容 completion 路径从静态联调凭证迁移到真实用户身份的方案,以及共享会话、主动取消、限流和滥用防护。
  • 是否存在多租户;若不存在,区域/组织数据范围如何表达。
  • 角色与字段级权限矩阵,尤其是联系人和精确位置。
  • SuperAgent 的部署方、数据处理条款、鉴权、MCP 回调认证与网络边界。
  • 数据库网络拓扑、只读账号、视图策略和审计能力。
  • 对话、工具调用和安全审计的存储位置与保留周期。
  • 面向真实火情功能的责任主体、免责声明和人工确认机制。

这些问题影响实现方向,应在对应 Feature 的 Definition of Ready 阶段确认,不在代码中自行假设。