主题
认证与安全机制
本文引用的源码文件
本文引用的文件
目录
引言
本文面向 Agent HTTP API 的认证与安全机制,聚焦以下目标:
- 说明 Bearer Token 验证流程、配对码生成、扩展端配对、Token 轮换与过期处理。
- 解释路径白名单机制,包括
allowedPaths配置语义与checkPath安全检查逻辑。 - 描述命令安全分级系统,包括黑名单过滤、灰名单确认、命令白名单/强制放行与执行权限控制。
- 说明 CORS 跨域策略:仅允许
chrome-extension://来源访问。 - 提供完整认证流程图、错误响应格式和安全最佳实践建议。
- 给出 curl 示例,展示认证请求与常见安全错误的处理方法。
本项目采用双进程架构:Chrome 扩展端(Manifest V3)通过本地 HTTP/WebSocket 调用 Agent(Node.js)。Agent 负责文件系统、命令执行、技能、MCP、长期记忆与 RAG 等能力;扩展端负责用户交互、工具编排与本地代理客户端通信。
章节来源
项目结构与安全边界
Agent 的安全入口集中在 HTTP 服务器路由中,所有需要认证的接口在解析业务参数前统一进行 Bearer Token 校验;无需认证的接口(如健康检查、配对)则受 CORS 与最小信息暴露策略保护。
graph TB Client["浏览器或本地脚本"] --> Server["Agent HTTP 服务器<br/>server.js"] Server --> Auth["认证模块<br/>auth.js"] Server --> Security["安全模块<br/>security.js"] Server --> Executor["命令执行器<br/>executor.js"] Server --> Config["配置模块<br/>config.js"] Server --> Memory["记忆路由<br/>memory/routes.js"] Server --> MCP["MCP 注册表<br/>mcp/registry.js"] Server --> Skill["技能注册表<br/>skill/registry.js"]
图表来源
章节来源
核心安全组件
- 认证模块:负责配对码生成、扩展端配对、Token 验证与活跃连接窗口管理。
- 安全模块:负责路径白名单校验、硬阻止目录保护、命令分级管控。
- HTTP 服务器:统一处理 CORS、认证、请求体大小限制、文件上传与业务路由。
- 配置模块:提供
workdir、allowedPaths、pairCodeTTL、commandTimeout、fileMaxSize等关键配置项。 - 扩展端客户端:发起配对、保存 Token、携带 Authorization 头调用受保护接口。
章节来源
- agent/src/auth.js#L1-L188
- agent/src/security.js#L1-L761
- agent/src/server.js#L235-L266
- agent/src/config.js#L21-L21
- src/background/local-agent-client.js#L269-L303
- src/options/toolbox-shared.js#L157-L184
系统架构总览
Agent 的认证与安全流程可概括为:
- 扩展端获取当前配对码并调用
/api/pair完成配对。 - 配对成功后获得 Token,后续请求携带
Authorization: Bearer <token>。 - 服务器对每个请求先做 CORS 预检与 Origin 校验,再解析 URL 与 body。
- 无需认证的接口直接返回最小必要信息;需要认证的接口先验 Token。
- 文件类接口使用
checkPath校验路径是否在白名单内。 - 命令类接口使用
checkCommand进行黑名单/灰名单分级判定。
sequenceDiagram
participant Ext as "扩展端"
participant Srv as "Agent 服务器"
participant Auth as "认证模块"
participant Sec as "安全模块"
Ext->>Srv : POST /api/pair {code, extensionId}
Srv->>Auth : handlePairRequest(code, extensionId)
Auth-->>Srv : {success, token|error}
Srv-->>Ext : {success, token|error}
Ext->>Srv : GET /api/status/detail (Authorization : Bearer token)
Srv->>Auth : verifyToken(token)
Auth-->>Srv : extId|null
alt 认证成功
Srv-->>Ext : {success, version, workdir, allowedPaths, ...}
else 认证失败
Srv-->>Ext : {success : false, error : "noToken"|invalidToken}
end
Ext->>Srv : POST /api/fs/read/write/list/delete/download (path)
Srv->>Sec : checkPath(path)
Sec-->>Srv : {allowed,resolved|reason}
alt 路径允许
Srv-->>Ext : 业务结果
else 路径拒绝
Srv-->>Ext : {success : false, error : reason}
end
Ext->>Srv : POST /api/exec (command, force?)
Srv->>Sec : checkCommand(command, force)
Sec-->>Srv : {safe,level,reason}
alt allow/deny
Srv-->>Ext : 执行结果或拒绝
else confirm
Srv-->>Ext : {needConfirm : true, reason}
end
图表来源
- agent/src/server.js#L471-L548
- agent/src/auth.js#L138-L179
- agent/src/security.js#L109-L229
- agent/src/security.js#L691-L758
详细组件分析
Bearer Token 认证与配对码机制
- 配对码生成:使用密码学安全的随机字节生成 6 位字母数字配对码,排除易混淆字符。
- 配对码轮换:启动时立即生成一次;定时按
pairCodeTTL刷新;当存在配对记录且最近 5 分钟内有过认证,则停止刷新;否则继续刷新以允许新扩展配对。 - 配对请求:校验 code 与 extensionId;连续失败 5 次后锁定 60 秒并立即轮换配对码;配对成功后立即轮换配对码,防止重复利用。
- Token 验证:每次成功认证更新
lastAuthTime;服务器从配对记录中查找匹配 token,返回扩展 ID。 - 已配对扩展横向防护:
/api/status/detail不再下发 pairCode,避免已配对端横向获取其他扩展的配对码。
flowchart TD
Start(["启动 Agent"]) --> GenCode["生成初始配对码"]
GenCode --> Timer["启动 TTL 定时器"]
Timer --> CheckActive{"有配对且最近活跃?"}
CheckActive --> |是| StopRotate["停止轮换配对码"]
CheckActive --> |否| RotateCode["轮换新配对码"]
RotateCode --> Timer
StopRotate --> Timer
PairReq["收到 /api/pair 请求"] --> Validate["校验 code 与 extensionId"]
Validate --> ValidCode{"配对码正确?"}
ValidCode --> |否| IncFail["失败计数+1"]
IncFail --> LockCheck{"达到失败阈值?"}
LockCheck --> |是| Lock["锁定 60 秒并轮换配对码"]
LockCheck --> |否| ReturnErr["返回错误"]
ValidCode --> |是| SavePairing["保存扩展 Token 并轮换配对码"]
SavePairing --> ReturnToken["返回 Token"]
图表来源
章节来源
- agent/src/auth.js#L30-L49
- agent/src/auth.js#L50-L60
- agent/src/auth.js#L75-L102
- agent/src/auth.js#L117-L127
- agent/src/auth.js#L138-L179
- agent/src/server.js#L471-L485
- agent/src/server.js#L537-L548
- agent/src/server.js#L724-L749
路径白名单与安全检查函数 checkPath
checkPath 是文件类接口的核心安全门控,其逻辑如下:
- 输入校验与
~展开。 - 路径格式规整:处理 MSYS/Git Bash 风格路径、盘符大写、反斜杠统一。
- 绝对路径解析与工作目录合并。
- 硬阻止检查:
.ai-helper-agent下的敏感配置文件、日志、回收站、技能状态等不可绕过。 - 系统目录白名单:记忆存储目录始终允许读写。
- 工作目录永远放行:即使未出现在
allowedPaths,也允许访问当前工作目录,但需 realpath 防符号链接绕过。 allowedPaths白名单匹配:若配置为空则回退到工作目录;否则使用前缀匹配快速判断。- realpath 二次校验:防止符号链接绕过,并对 realPath 再次做硬阻止与前缀检查。
- 最终返回
{allowed, resolved|reason}。
flowchart TD
Enter(["进入 checkPath"]) --> Normalize["路径格式规整与 ~ 展开"]
Normalize --> Resolve["解析绝对路径"]
Resolve --> HardBlock{"命中硬阻止目录?"}
HardBlock --> |是| DenyHard["拒绝:禁止访问 Agent 敏感文件"]
HardBlock --> |否| MemoryCheck{"是否记忆存储目录?"}
MemoryCheck --> |是| AllowMemory["允许:记忆目录"]
MemoryCheck --> |否| WorkdirCheck{"是否在工作目录下?"}
WorkdirCheck --> |是| RealpathWorkdir["realpath 防符号链接绕过"]
RealpathWorkdir --> AllowWorkdir["允许:工作目录"]
WorkdirCheck --> |否| AllowedPathsCheck{"是否在 allowedPaths 白名单?"}
AllowedPathsCheck --> |否| DenyNotAllowed["拒绝:路径不在允许目录"]
AllowedPathsCheck --> |是| RealpathAllowed["realpath 二次校验"]
RealpathAllowed --> HardBlockReal{"realPath 命中硬阻止?"}
HardBlockReal --> |是| DenyHardReal["拒绝:禁止访问 Agent 敏感文件"]
HardBlockReal --> |否| PrefixReal["realPath 前缀匹配"]
PrefixReal --> AllowFinal["允许:路径有效"]
图表来源
章节来源
- agent/src/security.js#L40-L60
- agent/src/security.js#L62-L100
- agent/src/security.js#L109-L229
- agent/src/server.js#L1036-L1050
- agent/src/server.js#L1052-L1087
- agent/src/server.js#L1089-L1110
- agent/src/server.js#L1112-L1142
- agent/src/server.js#L1144-L1161
- agent/src/server.js#L1163-L1200
命令安全分级系统
命令安全分为三个层级:
- 黑名单(deny):绝对禁止,force 不可绕过。包括递归删除系统目录、格式化磁盘、覆盖
/etc/passwd、fork bomb、shebang 直接执行、管道执行 shell 等。 - 灰名单(confirm):需要真实用户确认,force 可跳过。包括 sudo/doas/runas、全局 npm install、pip install/uninstall、chmod 777、rm -rf、git push -f、shutdown/reboot、eval、dd/shred/truncate、chmod/chown、curl/wget/ssh 等网络与进程操作、脚本解释器执行外部文件等。
- 白名单(allow):通过安全检查,直接执行。
命令扫描会逐段拆分链式命令、剥壳包装器(sudo/nohup/env 等)、提取解释器内联载荷(-c/-e、/c /k、PowerShell -Command/-EncodedCommand),并单独扫描命令替换($( ) 与反引号)中的子命令。黑名单始终生效;灰名单在 force 模式下跳过。
flowchart TD
CmdEnter(["进入 checkCommand"]) --> Trim["去除空白"]
Trim --> Scopes["收集子命令范围<br/>原始串 + 链式拆分 + 包装器剥壳 + 内联载荷 + 命令替换"]
Scopes --> Blacklist{"命中黑名单?"}
Blacklist --> |是| DenyCmd["拒绝:dangerous command"]
Blacklist --> |否| ForbiddenFile{"命令包含 Agent 敏感文件?"}
ForbiddenFile --> |是| DenyForbidden["拒绝:forbidden agent file"]
ForbiddenFile --> |否| ForceCheck{"force 模式?"}
ForceCheck --> |是| AllowForce["允许:用户已确认"]
ForceCheck --> |否| Graylist{"命中灰名单?"}
Graylist --> |是| ConfirmCmd["确认:需要用户确认"]
Graylist --> |否| AllowSafe["允许:安全命令"]
图表来源
章节来源
- agent/src/security.js#L231-L384
- agent/src/security.js#L386-L683
- agent/src/security.js#L691-L758
- agent/src/server.js#L1610-L1630
- agent/src/server.js#L1850-L1870
CORS 跨域策略
CORS 策略严格限制为仅允许 chrome-extension:// 来源:
getAllowedOrigin仅当origin以chrome-extension://开头时返回该 origin。- JSON 响应辅助函数
jsonResponse仅在允许 origin 时设置Access-Control-Allow-Origin与Vary: Origin。 - OPTIONS 预检请求同样遵循该策略。
- 恶意网页无法读取无认证端点(如
/api/status、/api/pair)的响应;非浏览器客户端(curl/脚本)不受 CORS 限制仍可访问。
flowchart TD
Req["HTTP 请求"] --> OriginCheck{"Origin 是否存在?"}
OriginCheck --> |否| NoACAO["不设置 ACAO"]
OriginCheck --> |是| ChromeExt{"是否 chrome-extension:// ?"}
ChromeExt --> |否| NoACAO
ChromeExt --> |是| SetACAO["设置 Access-Control-Allow-Origin = Origin"]
SetACAO --> Response["返回响应"]
NoACAO --> Response
图表来源
章节来源
扩展端与 Agent 端的认证协作
扩展端在配对成功后保存 Token,并在后续请求中携带 Authorization: Bearer <token>。options 面板的通用 Agent API 请求函数也会自动注入该头部,并对记忆写入端点附加 X-Memory-Caller: user 以声明可信来源。
sequenceDiagram
participant UI as "扩展端 UI"
participant Client as "local-agent-client.js"
participant Options as "toolbox-shared.js"
participant Server as "Agent 服务器"
UI->>Client : 触发配对
Client->>Server : POST /api/pair
Server-->>Client : {success, token}
Client->>Client : 保存 state.agentToken
UI->>Options : 调用 agentApi(method, path, body)
Options->>Options : 注入 Authorization : Bearer token
Options->>Server : HTTP 请求
Server-->>Options : JSON 响应
图表来源
章节来源
依赖关系分析
Agent 的安全依赖关系如下:
- server.js 依赖 auth.js 进行 Token 验证与配对码管理。
- server.js 依赖 security.js 进行路径与命令安全检查。
- security.js 依赖 config.js 获取
workdir、allowedPaths、MEMORY_DIR等配置。 - executor.js 依赖 security.js 的命令分级结果决定是否执行或要求确认。
- memory/routes.js 依赖 X-Memory-Caller 头区分模型与用户来源。
graph LR Server["server.js"] --> Auth["auth.js"] Server --> Security["security.js"] Server --> Executor["executor.js"] Security --> Config["config.js"] Executor --> Security Memory["memory/routes.js"] --> Server
图表来源
章节来源
性能与资源限制
- 请求体大小限制:JSON body 最大 200MB,multipart/form-data 同样限制。
- 流式上传:按接收字节累计超限即中断写入并清理半成品文件。
- 文件读取大小限制:默认 50MB,可通过
fileMaxSize配置调整。 - 搜索最大结果数:单次搜索最多 5000 条。
- 重启/更新冷却时间:10 秒冷却,防止频繁操作导致 DoS。
- 命令超时:默认 300 秒,可通过
commandTimeout配置调整。
章节来源
- agent/src/server.js#L132-L136
- agent/src/server.js#L271-L303
- agent/src/server.js#L310-L383
- agent/src/server.js#L805-L861
- agent/src/server.js#L722-L749
- agent/src/server.js#L519-L534
- agent/src/server.js#L605-L619
- agent/src/config.js#L21-L21
故障排查指南
常见认证与安全错误及处理建议:
- 401 无 Token:检查是否携带
Authorization: Bearer <token>。 - 403 Token 无效:检查 Token 是否正确、是否过期、是否被轮换。
- 403 路径不在允许目录:检查
allowedPaths配置是否包含目标路径。 - 403 禁止访问 Agent 敏感文件:检查是否尝试访问
.ai-helper-agent下的敏感文件或通过符号链接绕过。 - 400 文件过大:检查
fileMaxSize与上传内容大小。 - 400 命令无效:检查命令是否为空或仅含空白字符。
- 403 危险命令被拦截:查看命令是否命中黑名单;如需执行,使用 force 模式并经用户确认。
- 409 操作进行中:等待冷却时间后重试。
- 429 操作过于频繁:根据提示等待指定秒数。
章节来源
- agent/src/server.js#L537-L548
- agent/src/server.js#L1036-L1050
- agent/src/server.js#L1052-L1087
- agent/src/security.js#L109-L229
- agent/src/security.js#L691-L758
- agent/src/server.js#L519-L534
- agent/src/server.js#L605-L619
结论与安全最佳实践
- 始终使用配对码完成一次性配对,避免 Token 泄露。
- 不要将 Agent 监听地址绑定到
0.0.0.0,除非明确需要远程访问并已做好网络隔离。 - 合理配置
allowedPaths,仅开放必要目录;工作目录应始终可控。 - 谨慎使用 force 模式执行命令,确保用户已确认高风险操作。
- 定期轮换配对码与检查 Token 有效性,避免长期使用同一 Token。
- 监控日志中的认证失败、路径拒绝与命令拦截事件,及时发现异常行为。
- 保持 Agent 版本与扩展端版本同步,确保接口契约一致。
[本节为总结性内容,不直接分析具体文件]
附录:curl 示例与错误对照
配对请求
bash
curl -X POST http://127.0.0.1:18910/api/pair \
-H "Content-Type: application/json" \
-d '{"code":"ABCD12","extensionId":"chrome-extension-id"}'可能返回:
{success:true, token:"..."}:配对成功。{success:false, error:"tooFrequent"}:配对失败锁定中。{success:false, error:"invalidCode"}:配对码错误或已轮换。
健康检查(无需认证)
bash
curl http://127.0.0.1:18910/api/status返回平台信息与运行状态,不包含敏感主机信息。
带 Token 的状态详情
bash
curl http://127.0.0.1:18910/api/status/detail \
-H "Authorization: Bearer YOUR_TOKEN"返回 workdir、allowedPaths、commandTimeout、fileMaxSize 等配置信息。
文件读取(需认证 + 路径白名单)
bash
curl -X POST http://127.0.0.1:18910/api/fs/read \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"path":"/absolute/path/to/file.txt"}'可能返回:
{success:true, content:"...", size:123}:读取成功。{success:false, error:"路径不在允许目录"}:路径不在allowedPaths。{success:false, error:"禁止访问 Agent 敏感文件"}:命中硬阻止目录。
命令执行(需认证 + 安全分级)
bash
curl -X POST http://127.0.0.1:18910/api/exec \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"command":"ls -la","force":false}'可能返回:
{safe:true, level:"allow"}:直接执行。{safe:false, level:"confirm", reason:"..."}:需要用户确认。{safe:false, level:"deny", reason:"..."}:黑名单拒绝,不可绕过。
常见错误对照表
| HTTP 状态 | 业务含义 | 常见原因 | 处理建议 |
|---|---|---|---|
| 401 | 缺少 Token | 未携带 Authorization 头 | 添加 Authorization: Bearer <token> |
| 403 | Token 无效 | Token 错误、已轮换或不存在 | 重新配对或检查 Token 来源 |
| 403 | 路径拒绝 | 不在 allowedPaths 或命中硬阻止 | 检查白名单配置与路径安全性 |
| 400 | 请求体过大 | JSON/body 超过 200MB | 减小请求体或使用流式上传 |
| 400 | 命令无效 | 命令为空或仅空白 | 检查命令参数 |
| 409 | 操作进行中 | 重启/更新冷却中 | 等待 10 秒后重试 |
| 429 | 操作过于频繁 | 冷却时间内重复请求 | 根据提示等待指定秒数 |
章节来源