9.8 KiB
9.8 KiB
AI Agent 系统安全评审
- 评审日期:2024-xx-xx
- 评审范围:当前开源仓库中的 CLI/Web 入口(
main.py、web_server.py)、核心模块(core/,modules/)、配置(config/)、静态前端(static/)及数据目录(data/,users/)。 - 评审目标:识别阻碍产品化落地的安全缺口,明确优先级与改进路径,作为后续全面加固(尤其是“终端隔离 + 多租户环境”)的依据。
1. 系统与数据现状
1.1 主要角色 & 组件
- CLI 入口 (
main.py):默认启动 Web 模式,直接在宿主机DEFAULT_PROJECT_PATH内读写文件。 - Web 服务 (
web_server.py):基于 Flask + Socket.IO,整合登录、文件操作、终端调度、任务工具调用,所有状态保存在单进程内存 + 本地文件夹。 - 用户与工作区 (
modules/user_manager.py):账号、邀请码、工作目录全部持久化到./data/*.json,未引入数据库或权限控制。 - 终端/命令执行 (
modules/terminal_manager.py,modules/persistent_terminal.py):调度宿主机 shell 进程,缺乏容器或 cgroup;多用户共享一台机器的真实文件系统。 - 静态前端 (
static/index.html,static/app.js):大体量单文件脚本,所有逻辑在浏览器中运行,没有打包、模块划分或安全加固。
1.3 第一阶段整改进展
- ✅ Secrets 与配置:所有 API key/账号信息已迁移至
.env,config/__init__.py启动时自动加载并校验,仓库不再存在明文 key。 - ✅ 终端容器化:实时终端与
run_command/run_python默认运行在my-agent-shellDocker 容器中,配额为 0.5 vCPU / 1GB 内存,项目目录通过卷挂载;宿主机仅负责持久化。 - ✅ 资源与并发控制:新增
PROJECT_MAX_STORAGE_MB、MAX_ACTIVE_USER_CONTAINERS等限制,写入前会进行配额检查,活跃用户达到上限时提供resource_busy页面提示。 - ✅ 系统提示:模型接收的环境信息仅包含容器挂载路径与资源上限,不再暴露宿主机真实路径。
1.4 第二阶段增量成果
- ✅ 单用户-单容器 + 文件代理:每次登录都会启动专属容器(
modules/user_container_manager.py),CLI/Web 终端、run_command、FileManager 读写都通过容器代理完成,宿主机只负责挂载与备份。 - ✅ 容器监控与前端可视化:
modules/container_monitor.py定期采集docker stats/inspect,UI 用量面板实时展示 CPU/内存/网络速率与磁盘配额,让管理员能快速审计资源。 - ✅ 联网配置与镜像补强:Dockerfile 新增
iputils-ping,.env默认启用bridge网络,确保容器在受控环境下具备最小联网能力。
1.2 关键数据资产
| 资产 | 存储位置 | 备注 |
|---|---|---|
| 模型/API 密钥 | config/api.py, 环境变量(未来) |
目前以明文写在仓库 |
| 管理员凭据 | config/auth.py |
包含固定用户名与 PBKDF2 哈希 |
| 用户账号/工作区索引 | data/users.json, data/invite_codes.json, users/<uid>/ |
JSON 文件无加密、无访问控制 |
| 对话与工具日志 | data/conversations/*, logs/ |
包含终端输出、上传文件、任务上下文 |
| 用户上传文件 | users/<uid>/project/user_upload |
与终端共享同一路径 |
2. 攻击面概览
- HTTP API:Flask 路由与 REST 接口缺乏 CSRF、防爆破、速率限制,
CORS(app)与cors_allowed_origins="*"允许任意来源发起请求。 - WebSocket/Socket.IO:所有事件透过会话 cookie 鉴权,没有额外的 token 或设备指纹,连接转发逻辑在内存字典
connection_users中维护。 - 文件上传/下载:
/api/upload、/api/gui/files/upload接受任意类型文件,未做恶意内容扫描,仅依赖MAX_UPLOAD_SIZE=50MB。 - 终端命令执行:浏览器或 API 调用可直接在宿主机 shell 运行命令,代码运行结果与项目文件落在真实文件系统。
- 配置与日志:所有 secrets、日志、备份位于仓库根目录,可被具备 shell 访问权的任意人读取。
3. 主要安全发现(按严重度排序)
| # | 严重度 | 问题 & 证据 | 影响 | 建议 |
|---|---|---|---|---|
| 1 | Critical | ✅ 执行环境隔离就绪:实时终端、run_command 与 FileManager 统统绑定用户专属容器,modules/container_file_proxy.py 保证写入只发生在 /workspace,宿主机仅承载挂载目录。 |
Web 用户仅能访问自己容器内的文件/进程;若容器崩溃可在宿主机安全回收。 | 持续关注容器逃逸与 runtime 补丁,下一步考虑 rootless Docker / gVisor 进一步降低宿主暴露面。 |
| 2 | Critical | 明文 API Key / Secret:config/api.py:3-25 存在硬编码模型 key,config/auth.py:1-7 暴露管理员用户名 + 哈希。 |
仓库一旦共享即泄漏密钥;攻击者可伪造管理员账户或重放 API 请求。 | 将所有 secrets 挪到环境变量 / Secret Manager,删除仓库中的明文;在启动时校验缺省值并阻止运行。 |
| 3 | High | Flask SECRET_KEY 固定且公开:web_server.py:54-58 将 SECRET_KEY='your-secret-key-here' 写死,且默认启用 CORS(*)。 |
攻击者可伪造 session cookie、冒充任意用户、解密/篡改会话。 | 将 SECRET_KEY 存储于环境变量,启用 SESSION_COOKIE_SECURE/HTTPONLY/SAMESITE,并限制 CORS 源。 |
| 4 | High | ✅ 鉴权与速率限制补强:登录/注册/文件等敏感接口统一接入速率限制与失败计数(按 IP/用户维度),Socket.IO 握手改为一次性 token + Session。 | 暴力破解和凭证滥用的窗口被显著压缩,WebSocket 不再能单靠 Cookie 劫持。 | 下一步考虑加入 CAPTCHA/MFA、失败告警以及对 CLI API 的 token 鉴权。 |
| 5 | High | ✅ 多租户容器化 + 读写代理:UserManager 登录即创建独立容器,FileManager 通过容器内脚本执行 create/read/write/modify,宿主机不再直接接触用户代码。 | 横向越权面大幅收窄:除非容器逃逸,否则无法读写他人目录。 | 下一步需在 API 层加上 workspace ACL 与审计日志,防止管理员 session 滥用。 |
| 6 | Medium | 用户与会话数据存储在本地 JSON:modules/user_manager.py:167-195 将账号、密码哈希、邀请码写入 data/users.json,没有备份策略、并发安全或加密。 |
易被本地用户读取/篡改;当并发写入时有数据损坏风险,也无法满足审计/恢复。 | 引入关系型数据库或托管身份服务;对敏感字段做透明加密,提供备份与迁移策略。 |
| 7 | Medium | ✅ CSRF + 安全头:所有写操作统一校验 X-CSRF-Token(匿名令牌 API + fetch 包装),并启用 SameSite/HttpOnly/Secure Cookie 与基础安全响应头。 |
浏览器无法再被第三方站点诱导执行写操作,Cookie 也具备最小暴露。 | 仍需结合 CSP/Referer 限制和子域隔离,防止潜在的 XSS 复合攻击。 |
| 8 | Medium | 文件上传仅做文件名校验:web_server.py:841-907, 985-1069 只调用 sanitize_filename_preserve_unicode,但未检测 MIME、内容或执行权限。 |
可上传脚本并经终端执行;针对 Windows/Unix 的路径和符号链接处理也未覆盖。 | 引入内容扫描(ClamAV/自建规则)、限制文件类型/数量,并将上传目录与执行目录隔离。 |
| 9 | Medium | 日志/终端信息缺乏审计与脱敏:logs/、data/conversations/ 中保留所有指令和模型输出,没有访问控制。 |
可能泄漏用户代码、密钥;出现安全事件时也很难追踪。 | 将日志写入集中式系统(ELK/ClickHouse),对敏感字段脱敏,建立查询与保留策略。 |
| 10 | Low | 配置默认值缺乏环境检测:如 DEFAULT_PROJECT_PATH="./project"、MAX_UPLOAD_SIZE=50MB 固定写入;main.py 未检查当前用户权限。 |
误配置可能导致数据写入到未知磁盘或权限不足引发异常。 | 在启动阶段校验运行环境(磁盘权限、必需目录、环境变量),并提供友好报错与文档。 |
4. 优先修复路线(建议迭代 0 → 2)
-
密钥治理与配置基线
- 移除所有硬编码 secrets,提供
.env.example;启动脚本在缺失密钥时直接失败。 - 配置 Flask session 安全选项、限制 CORS 来源、添加基本安全 HTTP 头。
- 移除所有硬编码 secrets,提供
-
执行环境隔离 PoC
- 选定容器技术(Docker/LXC/Firecracker),将
TerminalManager改造为“容器调度器”,所有命令走容器内的/workspace目录。 - 引入任务代理服务(FastAPI + Celery/RabbitMQ)分离 Web API 与执行层,给每个用户/对话绑定独立容器生命周期。
- 选定容器技术(Docker/LXC/Firecracker),将
-
身份/鉴权与数据持久化升级
- 使用数据库管理用户、会话与权限,加入账号锁定、审计日志、API rate limit。
- 为日志、对话、上传文件建立访问控制与加密策略,提供备份/恢复。
-
安全运维体系
- 落地集中日志、异常告警、指标监控;在部署脚本中加入 CIS/Baseline 检查。
- 定期执行依赖扫描(pip-audit/Dependabot)、容器镜像漏洞检测,并把密钥轮换流程流程化。
5. 后续工作与协作建议
- 建议在
docs/中维护《安全基线》《运维手册》《应急预案》,并在 PR 模板中新增安全检查项。 - 组建最小安全清单:每次上线前确认终端隔离、密钥、日志、鉴权、备份五项指标均处于“通过”状态。
- 在完成 PoC 后,再讨论“前端重写、UI 组件化”等体验向任务,确保基础安全能力可复用到后续版本。
本文档会随着重构推进持续更新;若需深入某一条风险(如容器隔离方案、密钥管理流程),可另开文档展开细化设计。