安全模型设计
CocoCat 的安全模型采用纵深防御策略:多层安全机制层层叠加,任何单层被突破都不会导致系统完全失陷。
安全层次总览
┌──────────────────────────────────────────────┐
│ 第 7 层:Linux 命名空间隔离 │ 可选,最强隔离
├──────────────────────────────────────────────┤
│ 第 6 层:API Key 认证 │ 外部服务访问
├──────────────────────────────────────────────┤
│ 第 5 层:JWT 认证 + WebSocket 验证 │ Web 面板访问
├──────────────────────────────────────────────┤
│ 第 4 层:文件锁 + 原子写入 │ 并发安全
├──────────────────────────────────────────────┤
│ 第 3 层:路径验证 │ 文件系统边界
├──────────────────────────────────────────────┤
│ 第 2 层:命令过滤 + 环境净化 │ 执行引擎
├──────────────────────────────────────────────┤
│ 第 1 层:权限级别 │ Tool 层面
└──────────────────────────────────────────────┘第 1 层:权限级别(Permission Mode)
每个 Tool 声明其所需的权限级别,ToolRegistry 在执行时检查:
python
class PermissionMode(Enum):
READONLY = "readonly" # 读操作
WORKSPACE_WRITE = "write" # workspace 内写操作
FULL_ACCESS = "full" # 完整访问
def __le__(self, other):
order = [READONLY, WORKSPACE_WRITE, FULL_ACCESS]
return order.index(self) <= order.index(other)当前运行模式由场景配置决定。如果 agent 处于 WORKSPACE_WRITE 模式,则不能调用需要 FULL_ACCESS 的工具(如 exec_command)。
第 2 层:沙箱层
CommandValidator
过滤危险 shell 命令模式:
- 禁止管道到 shell(
| bash,| sh) - 禁止危险命令(
rm -rf /,dd if=等) - 禁止 URL 请求(SSRF 防护)
- 禁止编码执行(base64 decode + execute 模式)
- 跨平台(Windows + Linux 双重检测)
EnvironmentSanitizer
在执行命令前清除环境变量中的敏感信息:
- 移除
*KEY*,*SECRET*,*TOKEN*,*PASSWORD*模式的环境变量 - 使用 blocklist 而非 whitelist(避免漏掉未预见的 secret 类型)
OutputTruncator
截断过长命令输出,防止输出洪泛导致上下文溢出:
- 默认
max_chars=10000 - 截断后标注
[Truncated X total chars]
第 3 层:路径验证(PathValidator)
所有文件操作工具(read_file, write_file, edit_file 等)在执行前都经过路径验证:
python
pv = PathValidator()
is_safe, reason = pv.validate(path, PROJECT_ROOT)
if not is_safe:
return f"Error: {reason}"检查内容:
- 路径必须在 workspace 目录内
- 禁止路径遍历(
../../etc/passwd) - 禁止符号链接逃逸
- Windows 平台处理大小写不敏感
第 4 层:并发安全
FileLock
跨平台文件锁,防止并发写入冲突:
- 使用锁文件(
.lock)实现 - 自动过期(stale lock 检测)
- 上下文管理器接口
atomic_write
原子写入模式:先写 .tmp 文件,再 rename 到目标路径。保证:
- 写入过程崩溃不会留下不完整的文件
- 读者不会看到半写状态
- 支持跨文件系统(Windows 上使用
replace)
第 5 层:JWT 认证
所有 Web API 端点(除 /api/auth/login)需要 Authorization: Bearer <JWT> 头:
python
@router.get("/api/agents")
async def list_agents(user=Depends(auth_required)):
...- WebSocket 连接也需 token 验证(通过 URL query 参数)
- Token 有过期时间(默认 480 分钟)
- JWT 包含 agent 身份信息用于审计
第 6 层:API Key 认证
外部服务通过 X-API-Key 头访问,适用于:
- 自动化脚本
- CI/CD 集成
- 第三方服务 webhook
第 7 层:Linux 命名空间隔离
可选的最强隔离层,仅 Linux 平台:
ini
LINUX_NAMESPACE_SANDBOX=true
LINUX_NETWORK_ISOLATION=true- 使用
unshare()系统调用创建隔离的命名空间 - 独立的 PID、挂载、网络命名空间
- 网络隔离时 Agent 完全无法访问外部网络
- 即使
exec_command被滥用,也局限在隔离环境内
为什么需要多层?
每一层解决不同的问题:
| 问题 | 对应层 |
|---|---|
| Agent 行为失控 | 权限级别限制工具范围 |
| Agent 执行恶意命令 | 命令过滤器禁止危险模式 |
| Agent 读写敏感文件 | 路径验证限制文件操作范围 |
| 并发写入数据损坏 | 文件锁 + 原子写入 |
| 未授权 Web 访问 | JWT 认证 |
| 未授权 API 访问 | API Key 认证 |
| 系统级逃逸 | Linux 命名空间隔离 |
单一安全层容易被绕过。纵深防御确保:即使某一层被突破,后续层仍然提供保护。