87 lines
9.3 KiB
Markdown
87 lines
9.3 KiB
Markdown
# 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-shell` Docker 容器中,配额为 0.5 vCPU / 1GB 内存,项目目录通过卷挂载;宿主机仅负责持久化。
|
||
- ✅ **资源与并发控制**:新增 `PROJECT_MAX_STORAGE_MB`、`MAX_ACTIVE_USER_CONTAINERS` 等限制,写入前会进行配额检查,活跃用户达到上限时提供 `resource_busy` 页面提示。
|
||
- ✅ **系统提示**:模型接收的环境信息仅包含容器挂载路径与资源上限,不再暴露宿主机真实路径。
|
||
|
||
### 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 | **执行环境无隔离**:`modules/persistent_terminal.py:87-178` 直接在宿主机上 `subprocess.Popen` shell,所有命令与文件操作共享真实系统。 | 任意 Web 用户可读取/修改宿主机文件、横向移动、破坏系统。 | 必须引入容器/VM 沙箱,将项目、依赖与命令执行限制在受控环境,并对资源设置限额(CPU/Mem/IO)。 |
|
||
| 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 | **鉴权与速率限制缺失**:登录接口没有 CAPTCHA/速率限制;`api_login_required` 仅检查 session;Socket.IO 连接未绑定 IP/指纹。 | 暴力破解、会话劫持、重放攻击均无防护;一旦 cookie 泄漏即可接管终端。 | 引入 Flask-Limiter 等中间件,记录失败次数,必要时强制多因子或设备锁定;WebSocket 握手附带一次性 token。 |
|
||
| 5 | High | **多租户数据无物理隔离**:虽然 `UserManager.ensure_user_workspace` 为每个用户创建子目录,但同一进程拥有全部路径读写权限,且 FileManager (`modules/file_manager.py`) 仅按“项目根目录”限制,无法阻止管理员会话访问他人目录。 | 横向越权风险高,任何被攻破的账号都可以遍历/窃取其他租户数据。 | 将每个用户放入独立容器/VM,并由调度服务负责映射;API 层使用数据库/ACL 校验 user_id 与路径的对应关系。 |
|
||
| 6 | Medium | **用户与会话数据存储在本地 JSON**:`modules/user_manager.py:167-195` 将账号、密码哈希、邀请码写入 `data/users.json`,没有备份策略、并发安全或加密。 | 易被本地用户读取/篡改;当并发写入时有数据损坏风险,也无法满足审计/恢复。 | 引入关系型数据库或托管身份服务;对敏感字段做透明加密,提供备份与迁移策略。 |
|
||
| 7 | Medium | **缺乏 CSRF、防重放与安全头部**:所有 POST/PUT 接口(如 `/api/gui/files/*`, `/api/upload`)均未校验 CSRF token。 | 登陆态用户可被恶意网站诱导发起操作(上传/删除/运行命令)。 | 在 Flask 层加入 CSRF 保护(WTF-CSRF 或自定义 token),并添加 Strict-Transport-Security、Content-Security-Policy 等响应头。 |
|
||
| 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)
|
||
|
||
1. **密钥治理与配置基线**
|
||
- 移除所有硬编码 secrets,提供 `.env.example`;启动脚本在缺失密钥时直接失败。
|
||
- 配置 Flask session 安全选项、限制 CORS 来源、添加基本安全 HTTP 头。
|
||
|
||
2. **执行环境隔离 PoC**
|
||
- 选定容器技术(Docker/LXC/Firecracker),将 `TerminalManager` 改造为“容器调度器”,所有命令走容器内的 `/workspace` 目录。
|
||
- 引入任务代理服务(FastAPI + Celery/RabbitMQ)分离 Web API 与执行层,给每个用户/对话绑定独立容器生命周期。
|
||
|
||
3. **身份/鉴权与数据持久化升级**
|
||
- 使用数据库管理用户、会话与权限,加入账号锁定、审计日志、API rate limit。
|
||
- 为日志、对话、上传文件建立访问控制与加密策略,提供备份/恢复。
|
||
|
||
4. **安全运维体系**
|
||
- 落地集中日志、异常告警、指标监控;在部署脚本中加入 CIS/Baseline 检查。
|
||
- 定期执行依赖扫描(pip-audit/Dependabot)、容器镜像漏洞检测,并把密钥轮换流程流程化。
|
||
|
||
---
|
||
|
||
## 5. 后续工作与协作建议
|
||
- 建议在 `docs/` 中维护《安全基线》《运维手册》《应急预案》,并在 PR 模板中新增安全检查项。
|
||
- 组建最小安全清单:每次上线前确认终端隔离、密钥、日志、鉴权、备份五项指标均处于“通过”状态。
|
||
- 在完成 PoC 后,再讨论“前端重写、UI 组件化”等体验向任务,确保基础安全能力可复用到后续版本。
|
||
|
||
> 本文档会随着重构推进持续更新;若需深入某一条风险(如容器隔离方案、密钥管理流程),可另开文档展开细化设计。
|