258 lines
13 KiB
Markdown
258 lines
13 KiB
Markdown
# 04 — 应用安全
|
||
|
||
> GB/T 22239-2019 第三级「应用和数据安全 — 应用部分」控制点映射。
|
||
|
||
## 1. 维度说明
|
||
|
||
应用安全是 AgentKit **自身核心责任范围**,全部 8 个控制点已实现。
|
||
本维度文档引用 U4 SSO 多 IDP / SCIM、U1 OTel 审计、R7a 终端安全 6 层、
|
||
RBAC 3 级权限、JWT 会话等既有实现,不重复代码细节。
|
||
|
||
## 2. GB/T 22239-2019 三级要求(简要)
|
||
|
||
| 控制点 ID | 要求摘要 |
|
||
|-----------|----------|
|
||
| APP-01 | 身份鉴别:用户身份标识与鉴别,口令复杂度,登录失败处理 |
|
||
| APP-02 | 访问控制:基于角色的访问控制,最小权限,默认拒绝 |
|
||
| APP-03 | 安全审计:应用审计日志,覆盖用户操作关键事件 |
|
||
| APP-04 | 通信完整性:传输完整性保护,防篡改 |
|
||
| APP-05 | 软件容错:错误处理,故障隔离,降级机制 |
|
||
| APP-06 | 资源控制:会话并发控制,超时自动断开 |
|
||
| APP-07 | 应用账户生命周期:开户/变更/销户审计,SCIM 自动化 |
|
||
| APP-08 | 代码安全:输入验证,输出编码,依赖漏洞管理 |
|
||
|
||
## 3. AgentKit 实现映射
|
||
|
||
### 3.1 身份鉴别(APP-01)— 已实现
|
||
|
||
#### 多 IDP 单点登录(U4 SSO)
|
||
|
||
AgentKit 支持 OIDC + SAML 双协议并存的多 IDP 信任边界:
|
||
|
||
- **OIDC 适配器**(authlib redirect flow + JIT 用户创建):
|
||
[src/agentkit/server/auth/providers/oidc.py](file:///Users/chiguyong/Code/Fischer-agentkit/src/agentkit/server/auth/providers/oidc.py)
|
||
- **SAML 2.0 适配器**(python3-saml / OneLogin ACS):
|
||
[src/agentkit/server/auth/providers/saml.py](file:///Users/chiguyong/Code/Fischer-agentkit/src/agentkit/server/auth/providers/saml.py)
|
||
- **多 IDP 注册表**(热证书轮换 + 单 IDP 故障隔离,R1a 按 sub 关联
|
||
禁止邮箱合并):
|
||
[src/agentkit/server/auth/idp_registry.py](file:///Users/chiguyong/Code/Fischer-agentkit/src/agentkit/server/auth/idp_registry.py)
|
||
|
||
支持的 IDP 类型:飞书 / Azure AD / 阿里云 IDaaS 等任意 OIDC/SAML 合规 IDP。
|
||
|
||
#### 本地密码认证
|
||
|
||
- **bcrypt 哈希**:rounds=12(OWASP 推荐值)
|
||
[src/agentkit/server/auth/password.py](file:///Users/chiguyong/Code/Fischer-agentkit/src/agentkit/server/auth/password.py)
|
||
- **JWT 会话**:HS256 签名,access 15min + refresh 7d(30d 记住我)
|
||
[src/agentkit/server/auth/jwt_utils.py](file:///Users/chiguyong/Code/Fischer-agentkit/src/agentkit/server/auth/jwt_utils.py)
|
||
- V2 claims 含 `sid`(session id)+ `jti`(per-token unique id),
|
||
支持服务端 session 撤销。
|
||
- **Refresh token 轮换 + reuse 检测**:旧 token 进入 denylist 30s 窗口,
|
||
reuse 触发撤销该用户全部 session
|
||
[src/agentkit/server/auth/denylist.py](file:///Users/chiguyong/Code/Fischer-agentkit/src/agentkit/server/auth/denylist.py)
|
||
- **登录失败处理**:JWT 验证失败返回 401,refresh token reuse 触发
|
||
全 session 撤销(强制重新登录)。
|
||
- **OAuth state CSRF 防护**:OIDC state 缓存 TTL 5min,一次性消费
|
||
([oidc.py](file:///Users/chiguyong/Code/Fischer-agentkit/src/agentkit/server/auth/providers/oidc.py) `_StateCache`)。
|
||
|
||
### 3.2 访问控制 / RBAC 3 级(APP-02)— 已实现
|
||
|
||
#### 3 级 RBAC + 9 权限位
|
||
|
||
[src/agentkit/server/auth/permissions.py](file:///Users/chiguyong/Code/Fischer-agentkit/src/agentkit/server/auth/permissions.py)
|
||
|
||
| 角色 | 权限 |
|
||
|------|------|
|
||
| `member` | CHAT / KB_QUERY / WORKFLOW_EXECUTE |
|
||
| `operator` | member 全部 + KB_WRITE + TERMINAL_LOCAL_USE + TERMINAL_WHITELIST_MANAGE |
|
||
| `admin` | operator 全部 + TERMINAL_SERVER_USE + USER_MANAGE + SYSTEM_CONFIG |
|
||
|
||
权限位作为稳定字符串标识符用于 JWT payload + 前端 store + 审计日志,
|
||
不重命名既有值(向前兼容)。
|
||
|
||
#### 终端安全 6 层白名单(R7a)
|
||
|
||
[src/agentkit/server/auth/terminal_security.py](file:///Users/chiguyong/Code/Fischer-agentkit/src/agentkit/server/auth/terminal_security.py)
|
||
|
||
评估优先级(最高→最低):
|
||
|
||
1. **Blocklist**(admin 管理,永远拒绝)
|
||
2. **Built-in safe whitelist**(`_SAFE_COMMAND_PREFIXES`)
|
||
3. **Global whitelist**(admin 管理,DB 持久化)
|
||
4. **User whitelist**(per-user,DB 持久化 + 内存缓存)
|
||
5. **Session whitelist**(per-session,仅内存)
|
||
6. **Danger detection**(`_is_dangerous`,需确认)
|
||
|
||
**关键安全特性**:shell 操作符(`&&`、`;`、`|`、`$()`、backticks、`>`、`<`、
|
||
换行)**永远绕过所有 whitelist 层**,强制走 danger detection —
|
||
即使 `git push` 在白名单中,`git push && rm -rf /` 仍需确认。
|
||
|
||
#### 终端双层授权
|
||
|
||
终端端点要求 RBAC 角色 + 个人授权标志双重校验:
|
||
|
||
- `is_terminal_authorized` — 本地终端(client sidecar)
|
||
- `is_server_terminal_authorized` — 服务端终端(server PTY)
|
||
|
||
允许 admin 按用户授权终端而不改变其角色。
|
||
|
||
#### SCIM token 恒定时间比较
|
||
|
||
SCIM bearer token 使用 `hmac.compare_digest` 恒定时间比较防时序攻击:
|
||
[src/agentkit/server/auth/scim/router.py](file:///Users/chiguyong/Code/Fischer-agentkit/src/agentkit/server/auth/scim/router.py)
|
||
(`_verify_scim_token`)。
|
||
|
||
### 3.3 安全审计(APP-03)— 已实现
|
||
|
||
#### OTel 审计通道(U1 强制依赖)
|
||
|
||
[src/agentkit/server/auth/audit.py](file:///Users/chiguyong/Code/Fischer-agentkit/src/agentkit/server/auth/audit.py)
|
||
|
||
审计事件类型:
|
||
|
||
- `role_change` — RBAC 角色变更(actor/target/role_before/role_after)
|
||
- `deprovision` — 手动 deprovisioning(含 `break_glass` 标记)
|
||
|
||
每条记录含 actor/target/reason/source/timestamp,写入 `auth_audit_log` 表
|
||
+ 发 OTel span event(OTel 不可用时降级为 SQLite + 日志)。
|
||
|
||
审计来源(`source` 字段):
|
||
|
||
- `manual` — 手动操作
|
||
- `scim` — SCIM 自动化
|
||
- `cron_reconciliation` — 定时对账
|
||
- `break_glass` — 应急通道(高权限账户)
|
||
|
||
#### SCIM 推送失败告警
|
||
|
||
SCIM push 失败实时告警:日志 error + OTel span event `scim.push.failure`
|
||
([scim/router.py](file:///Users/chiguyong/Code/Fischer-agentkit/src/agentkit/server/auth/scim/router.py)
|
||
`_alert_scim_failure`)。
|
||
|
||
#### 终端命令审计
|
||
|
||
每条终端命令 + 决策结果(executed/confirmed/rejected/blocked/denied)
|
||
+ cwd + exit_code 写入 `terminal_audit_logs` 表
|
||
([terminal_security.py](file:///Users/chiguyong/Code/Fischer-agentkit/src/agentkit/server/auth/terminal_security.py)
|
||
`write_audit_log`)。
|
||
|
||
#### OTel 指标
|
||
|
||
U1 OTel 暴露以下审计相关指标
|
||
([src/agentkit/telemetry/metrics.py](file:///Users/chiguyong/Code/Fischer-agentkit/src/agentkit/telemetry/metrics.py)):
|
||
|
||
- `agent.request.total` / `agent.execution.duration`
|
||
- `gen_ai.usage.tokens` / `tool.call.duration`
|
||
- `prompt_cache.hit` / `prompt_cache.miss`
|
||
- `pii_filter.coverage` / `pii_filter.redacted`(U2 PII 脱敏覆盖率)
|
||
|
||
### 3.4 通信完整性(APP-04)— 已实现
|
||
|
||
- **传输层 TLS**:Ingress TLS 终止(详见 `02-network.md` §3.2),
|
||
客户端→Ingress 全程 HTTPS。
|
||
- **JWT 签名完整性**:HS256 签名,任何 payload 字段篡改导致签名校验失败
|
||
([jwt_utils.py](file:///Users/chiguyong/Code/Fischer-agentkit/src/agentkit/server/auth/jwt_utils.py)
|
||
`verify_token`)。
|
||
- **mTLS 客户端证书**(下游服务):Helm Chart 预留 `secrets.mtlsClientCert`
|
||
slot,用于与 KMS/HSM、内部 API 双向 TLS(详见 `06-management.md`)。
|
||
- **Webhook 签名校验**:入站 Webhook fail-closed,签名校验失败返回 401
|
||
([channels.py](file:///Users/chiguyong/Code/Fischer-agentkit/src/agentkit/server/routes/channels.py))。
|
||
|
||
### 3.5 软件容错(APP-05)— 已实现
|
||
|
||
- **LLM 网关 fallback**:多 provider fallback 链
|
||
([src/agentkit/llm/gateway.py](file:///Users/chiguyong/Code/Fischer-agentkit/src/agentkit/llm/gateway.py))。
|
||
- **OTel 运行时容错**:OTel exporter 连接失败时降级为 NoOpTracer,
|
||
应用启动不崩溃([tracer.py](file:///Users/chiguyong/Code/Fischer-agentkit/src/agentkit/telemetry/tracer.py)
|
||
`init_telemetry`)。
|
||
- **PII 脱敏 fail-closed**:脱敏异常时拒绝发送至 LLM,不降级到原文
|
||
([pii_filter.py](file:///Users/chiguyong/Code/Fischer-agentkit/src/agentkit/llm/pii_filter.py)
|
||
`fail_closed=True` 默认)。
|
||
- **专家团队失败回退**:所有阶段失败时回退到单 agent 模式
|
||
(详见 AGENTS.md「专家团队模式」)。
|
||
- **DR-fixes(U3)**:bitable 字段校验(DR-1)、LastViewDeletionError(DR-4)、
|
||
工具调用容错(DR-5)。
|
||
- [src/agentkit/bitable/repository.py](file:///Users/chiguyong/Code/Fischer-agentkit/src/agentkit/bitable/repository.py)
|
||
- [src/agentkit/bitable/service.py](file:///Users/chiguyong/Code/Fischer-agentkit/src/agentkit/bitable/service.py)
|
||
- [src/agentkit/tools/bitable_tool.py](file:///Users/chiguyong/Code/Fischer-agentkit/src/agentkit/tools/bitable_tool.py)
|
||
|
||
### 3.6 资源控制(APP-06)— 已实现
|
||
|
||
- **IP 限流**:[RateLimiter](file:///Users/chiguyong/Code/Fischer-agentkit/src/agentkit/server/middleware.py)
|
||
滑动窗口(`max_requests` / `window_seconds` 可配置)。
|
||
- **Webhook 独立限流**:[channels.py](file:///Users/chiguyong/Code/Fischer-agentkit/src/agentkit/server/routes/channels.py)
|
||
入站端点单独限流 + nonce dedup。
|
||
- **会话超时**:
|
||
- 终端 session 闲置 1800s 自动断开
|
||
([terminal_server.py](file:///Users/chiguyong/Code/Fischer-agentkit/src/agentkit/server/routes/terminal_server.py))。
|
||
- JWT access token 15min 过期强制重新认证。
|
||
- **专家名称正则校验**:`_EXPERT_NAME_RE = re.compile(r"^[a-zA-Z0-9_-]{1,64}$")`
|
||
防止注入(项目规则)。
|
||
- **HandoffTransport 有界队列**:`maxsize=1024`,关闭使用 sentinel 模式
|
||
防止无界内存增长(项目规则)。
|
||
|
||
### 3.7 应用账户生命周期 / SCIM(APP-07)— 已实现
|
||
|
||
#### SCIM 2.0 自动化
|
||
|
||
[src/agentkit/server/auth/scim/router.py](file:///Users/chiguyong/Code/Fischer-agentkit/src/agentkit/server/auth/scim/router.py)
|
||
|
||
端点:
|
||
|
||
- `POST /scim/v2/Users` — 创建用户(随机密码,不可本地登录)
|
||
- `PATCH /scim/v2/Users/{id}` — 禁用(active=false)/ 更新字段
|
||
- `GET /scim/v2/Users` — 列表 / 过滤(`userName eq` / `active eq`)
|
||
|
||
Bearer token 认证(独立于 JWT,恒定时间比较)。
|
||
|
||
#### Deprovisioning(账户销户)
|
||
|
||
管理员通过 `/admin/users/{id}/deprovision` 强制销户:
|
||
|
||
1. 禁用本地用户账户(`is_active = 0`)
|
||
2. 撤销该用户所有活跃 session
|
||
3. 记录审计(actor/target/reason/source/timestamp)+ OTel
|
||
4. `break_glass=True` 时记录 `source=break_glass`(应急通道标记)
|
||
|
||
详见 `06-management.md` §2 break-glass 告警流程。
|
||
|
||
#### JIT 用户创建(R1a)
|
||
|
||
OIDC/SAML 首次登录 JIT 创建本地用户 + `user_idp_links` 行,
|
||
按 `(idp_name, sub)` 严格关联,**禁止邮箱合并**已存在账户
|
||
([oidc.py](file:///Users/chiguyong/Code/Fischer-agentkit/src/agentkit/server/auth/providers/oidc.py)
|
||
`_find_or_create_user`)。
|
||
|
||
### 3.8 代码安全(APP-08)— 已实现
|
||
|
||
- **输入验证**:所有 API 入口使用 Pydantic v2 模型校验
|
||
(`model_config = ConfigDict(extra="forbid")` 拒绝额外字段)。
|
||
- SCIM 模型:[src/agentkit/server/auth/scim/models.py](file:///Users/chiguyong/Code/Fischer-agentkit/src/agentkit/server/auth/scim/models.py)
|
||
- IDP 配置:[src/agentkit/server/auth/idp_registry.py](file:///Users/chiguyong/Code/Fischer-agentkit/src/agentkit/server/auth/idp_registry.py)
|
||
(`OIDCConfig` / `SAMLConfig` 均 `extra="forbid"`)
|
||
- **禁止 `any` 类型**:项目规则强制使用 Pydantic 模型或 `Unknown`
|
||
(AGENTS.md)。
|
||
- **专家名称正则校验**:`_EXPERT_NAME_RE` 防 SQL/命令注入。
|
||
- **API Key 恒定时间比较**:`hmac.compare_digest`(项目规则)。
|
||
- **Ruff lint + format**:`ruff check src/ && ruff format src/`(目标 py311)
|
||
作为代码质量基线。
|
||
- **依赖管理**:`pyproject.toml` 锁定精确版本,`pip install -e ".[dev]"`
|
||
可复现环境。
|
||
- **终端命令安全**:6 层白名单 + shell 操作符检测
|
||
(详见 §3.2),防止命令注入链。
|
||
|
||
## 4. 测评建议
|
||
|
||
应用安全维度全部控制点已实现,测评时直接展示对应代码文件即可:
|
||
|
||
1. **APP-01**:展示 oidc.py / saml.py / jwt_utils.py / password.py。
|
||
2. **APP-02**:展示 permissions.py / terminal_security.py + RBAC 矩阵表。
|
||
3. **APP-03**:展示 audit.py + 终端审计日志 + OTel 指标清单。
|
||
4. **APP-04**:展示 ingress.yaml TLS + jwt_utils.py 签名校验 + channels.py
|
||
Webhook 签名。
|
||
5. **APP-05**:展示 gateway.py fallback + pii_filter.py fail-closed +
|
||
DR-fixes 引用。
|
||
6. **APP-06**:展示 middleware.py 限流 + terminal_server.py 超时。
|
||
7. **APP-07**:展示 scim/router.py + deprovision 端点 + JIT 创建逻辑。
|
||
8. **APP-08**:展示 Pydantic 模型校验 + Ruff 配置 + 终端命令安全。
|