安全:Root-Based 路径验证与遥测设计
安全:Root-Based 路径验证与遥测设计
学习目标
本章分析 Chrome DevTools MCP 的安全机制和遥测系统。你将理解:
- MCP
roots/list协议与 Workspace Roots 白名单机制 validatePath()的 canonical path 解析与路径匹配- 临时文件 vs 工作目录文件的区别
- ClearcutLogger 遥测系统的异步持久化
- 隐私保护:敏感请求头脱敏与遥测开关
前置知识
- 安全沙箱设计 — 多层防御架构
项目实践
Workspace Roots 白名单机制
项目通过 MCP 的 roots/list 协议获取 Agent 的工作区目录:
server.oninitialized = () => { if (server.getClientCapabilities()?.roots) { void updateRoots(); // 请求 MCP Client 发送 roots server.setNotificationHandler( RootsListChangedNotificationSchema, () => { void updateRoots(); } // 监听 roots 变化 ); }};自动追加临时目录:
roots(): Root[] { return [ ...this.#roots, { uri: pathToFileURL(os.tmpdir()).href, name: 'temp' }, ];}这允许工具将文件保存到系统临时目录(如截图、Trace),即使该目录不在 workspace roots 中。
validatePath() 路径校验
validatePath(filePath): 1. resolveCanonicalPath(filePath) → 获取真实路径(解析 symlinks) 2. 遍历每个 root: a. fileURLToPath(root.uri) → URI 转本地路径 b. fsPromises.realpath(rootPath) → 获取真实根路径 c. 检查 canonicalPath === root 或 startsWith(root + path.sep) 3. 若不在任何 root 内 → 抛出 "Access denied"安全考虑:
- 使用
realpath而非resolve:解析 symlinks,防止符号链接逃逸 startsWith(root + path.sep)而非startsWith(root):防止/tmp匹配到/tmp-data- 静默跳过无法解析的 root(
console.warn而非抛出异常)
两种文件保存方式
| 方法 | 用途 | 路径校验 | 目录结构 |
|---|---|---|---|
saveTemporaryFile | 截图、Trace 等临时文件 | 必须在 roots 内 | 使用 os.tmpdir() 或自定义临时目录 |
saveFile | 用户指定的保存路径 | 必须在 roots 内 | 按用户指定路径创建目录结构 |
网络请求头脱敏
--redactNetworkHeaders 标志启用时,敏感请求头(如 Authorization、Cookie)在返回给 Agent 前被脱敏:
setRedactNetworkHeaders(true): → 在 NetworkFormatter 中过滤敏感头 → 返回 "Authorization: [REDACTED]"默认关闭:因为调试场景通常需要查看完整请求头。
ClearcutLogger 遥测系统
ClearcutLogger.logToolInvocation({ toolName, params, schema, success, latencyMs}): ↓ 持久化到本地文件(FilePersistence) ↓ 异步发送到 Google Clearcut 端点 ↓ 延迟桶化(bucketizeLatency)而非发送精确毫秒遥测开关:
| 条件 | 效果 |
|---|---|
--no-usage-statistics | 禁用 |
CI=true 环境变量 | 禁用 |
CHROME_DEVTOOLS_MCP_NO_USAGE_STATISTICS | 禁用 |
延迟桶化:发送的是延迟区间(如 “100-500ms”)而非精确值,减少数据量。
设计取舍
| 取舍 | 选择 | 原因 |
|---|---|---|
| realpath vs resolve | realpath | 防止符号链接绕过白名单 |
| 白名单 vs 黑名单 | 白名单 | 默认拒绝,更安全 |
| 精确延迟 vs 桶化 | 桶化 | 保护隐私,减少数据量 |
| 遥测默认开启 vs 默认关闭 | 默认开启 | 提高数据覆盖率,但提供明确退出选项 |
陷阱与对策
| 陷阱 | 后果 | 对策 |
|---|---|---|
| symlink 指向白名单外 | 路径绕过 | 使用 realpath 解析 |
| root 路径包含空格或特殊字符 | startsWith 误判 | 使用 path.sep 精确匹配 |
| 遥测文件过大 | 磁盘占用 | FilePersistence 定期清理旧日志 |