136 lines
13 KiB
Markdown
136 lines
13 KiB
Markdown
# 安全与访问控制边界
|
||
|
||
| 项 | 内容 |
|
||
| --- | --- |
|
||
| 项目 | `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 阶段确认,不在代码中自行假设。
|