安全架构:从客户端到出口节点的六段信任边界
快喵VPN 把整条链路切分为 6 段信任边界,每段持有独立密钥与独立校验方式。在 2026 年 9 月的受控测试中,替换其中任意一段都会在第 1 个数据包内被判定,连接随即中断,不会降级为明文放行。
架构总览与边界划分
信任边界不是画在图上的线,而是密钥归属发生变化的位置。跨过一条边界,就要换一套校验方式。
判断一个架构是否可信,最直接的方法是数一数密钥在几处出现。快喵的链路里有 6 处会接触到密钥或拓扑信息:本地进程、系统网络栈、本地网关、接入节点、出口节点与控制面。它们之间不共享凭据,任何一处的失守都不会自动扩散到下一处。
六条边界各自防什么
- 边界 1 进程与内核 防本地提权后读取会话密钥。密钥只存在于加密内存区,进程退出即清零,不写入交换文件。
- 边界 2 客户端与本地网关 防同一网络内的被动嗅探。隧道封装在数据离开网卡前完成,明文不出主机。
- 边界 3 本地网关与接入节点 防链路中间人。双向证书校验,接入节点必须出示由内部 CA 签发的证书。
- 边界 4 接入节点与出口节点 防节点侧旁路。接入节点只见密文与目标地址的加密形态,不见正文。
- 边界 5 出口节点与目标站点 防站点侧关联。出口以共享地址访问,站点无法反推具体用户。
- 边界 6 控制面与数据面 防配置被篡改。控制面只下发策略不下发密钥,二者走独立通道。
| 边界 | 校验方式 | 校验频率 | 失守后的影响 | 隔离手段 |
|---|---|---|---|---|
| 进程与内核 | 内存加密区 + 进程完整性检查 | 每次启动 | 仅影响本机会话 | 密钥不落盘,退出清零 |
| 客户端与网关 | 隧道封装 + 认证标签 | 每个数据包 | 单包被丢弃并触发重连 | 无明文回退路径 |
| 网关与接入节点 | 双向证书 + 公钥固定 | 每次握手 | 握手失败,保留上次可用配置 | 证书固定到内部 CA |
| 接入与出口节点 | 节点间独立隧道 | 每条节点链路 | 该节点被摘除,流量改道 | 节点集合动态下发 |
| 出口与站点 | 共享出口 + 连接级复用 | 每连接 | 仅影响该出口地址 | 多地址轮换 |
| 控制面与数据面 | 签名校验 + 版本比对 | 每次配置变更 | 拒绝新配置,沿用旧版本 | 策略与密钥分离 |
这张表有两个容易被忽略的行:第三行的公钥固定,让它无法通过换一张伪造证书来伪装成接入节点;第六行的策略与密钥分离,让即使配置文件被替换也无法解密既有流量。两处加起来,把被动监听的收益压到接近零。
客户端:密钥与权限最小化
客户端是唯一同时持有明文与会话密钥的位置,因此它的权限清单必须能被逐项解释。
客户端申请的权限越多,被滥用的面就越大。快喵的做法是把权限压到与功能一一对应的最小集,并在安装界面上逐条说明用途。以 Windows 客户端为例,安装包体积 28.6 MB,安装后常驻内存约 96 MB,除虚拟网卡驱动外不注册任何系统级服务。
权限清单与用途
| 权限或组件 | 是否必需 | 用途 | 可否拒绝 | 拒绝后的表现 |
|---|---|---|---|---|
| 虚拟网卡驱动 | 必需 | 建立到接入节点的隧道设备 | 否 | 无法连接 |
| 网络配置修改 | 必需 | 写入路由与 DNS 指向隧道 | 否 | 无法接管流量 |
| 开机自启 | 可选 | 断线后自动恢复连接 | 是 | 需手动启动 |
| 本地通知 | 可选 | 推送风险事件与升级提示 | 是 | 提示改在应用内显示 |
| 诊断日志导出 | 可选 | 用户主动导出事件摘要 | 是 | 申诉时缺少证据 |
| 通讯录与相册 | 不申请 | —— | —— | —— |
密钥在客户端内的生命周期
会话密钥从派生到销毁全程不离开进程内存,且不经过系统的凭据管理器——这是刻意选择:凭据管理器会持久化,一旦被读取就等于长期持有。实测中,密钥在内存中的存活时间等于会话时长,断开后 0 毫秒即执行清零,随后的内存快照中检索不到密钥字节。
- 派生位置 在客户端进程内由握手共享秘密经 HKDF-SHA256 派生,接入节点独立派生同一结果,不做传输。
- 存放方式 仅存于进程私有内存页,禁用交换到磁盘,不写入任何配置文件。
- 销毁时机 会话结束、网络切换或用户手动断开时立即清零,并覆盖一次占位写入。
- 复述防护 同一会话内禁止密钥复用,重连必须重新协商,不复用上次会话的上下文。
打开诊断页的事件日志,可以看到每次会话的派生时间戳与销毁时间戳;两个字段之间没有任何密钥内容。若日志中出现密钥片段,说明实现有缺陷,请立即通过安全邮箱反馈。
接入层:协商与转发
接入节点是链路上唯一同时看到来源与去向的角色,因此它被设计成几乎不保存任何状态。
接入节点承担三项工作:与客户端完成握手、校验凭据、把密文转发到出口节点。它不终止面向站点的 TLS,也不解析正文。节点侧对单个连接的内存占用约 210 KB,因此在 16 GB 内存的实例上可同时维持约 3.8 万个活跃会话。
握手阶段的三个动作
- 证书出示接入节点出示内部 CA 签发的证书,客户端比对固定指纹,任一不符即中断并记录事件。
- 凭据校验客户端提交短期会话令牌,令牌有效期 15 分钟,不携带账号明文,也不写入节点磁盘。
- 密钥协商双方以 X25519 交换临时公钥,派生会话密钥;协商结果不落地,仅存于进程内存。
- 转发建立按控制面下发的节点表选择出口,建立节点间独立隧道,客户端流量进入转发队列。
节点侧不保存什么
- 不保存访问目标 转发队列只按会话 ID 索引,目标地址在密文头内,节点不解包。
- 不保存正文 节点无解密能力,正文以站点自己的 TLS 加密,节点侧无法解析。
- 不保存来源地址 来源地址仅存在于 NAT 映射表的内存条目中,断开即释放。
- 不保存令牌 令牌校验通过后立即丢弃,不在内存中保留副本。
出口层:隔离与共享出口
共享出口既是隐私手段,也是隔离手段:同一地址承载多个会话,单条记录无法反推到人。
出口层的设计目标有两个:让目标站点看到的地址与用户真实地址无关;让一个出口地址上的异常不扩散到其他用户。快喵对每个出口地址设置独立的速率窗口与并发上限,单个会话触发异常时只影响该会话所属的连接。
共享出口的工程约束
| 项目 | 取值 | 作用 | 越界处理 | 可观察现象 |
|---|---|---|---|---|
| 单出口并发会话 | 上限 480 个 | 避免单地址被大量请求标记 | 新会话改派其他出口 | 连接目标地址变化 |
| 单会话速率窗口 | 10 分钟滑动窗口 | 抑制异常流量 | 超限后限速而非断开 | 速度下降,连接保持 |
| 出口地址池 | 每区域 12 至 40 个地址 | 分散请求来源 | 按健康度动态剔除 | 透明换址重连 |
| 连接级复用 | 同一站点复用同一隧道连接 | 减少握手次数 | 复用超时后重建 | 首屏更快 |
| 异常隔离 | 按会话 ID 隔离 | 防止连带影响 | 仅该会话被降级 | 其他会话无感知 |
为什么不做独占出口
独占出口看起来更干净,但会让出口地址与账号形成一一对应,一旦该地址出现在某次记录中,即可定位到唯一用户——这恰好与无日志政策的目标相反。快喵保留共享出口作为默认,仅在需要固定地址的少数企业场景提供独立出口,并在文档中明确其隐私代价。
- 默认共享 同一出口地址同时服务多个会话,出站记录无法反推到具体账号。
- 企业独立出口 需要固定地址做白名单时提供,代价是可被反推,需在合同中单独确认。
- 地址轮换 按健康度与时间轮换,轮换过程对用户透明,不中断已建立的连接。
控制面与配置下发
控制面只下策略,不下密钥;它被攻破的后果是配置错误,而不是流量可读。
控制面负责节点健康度、线路权重与风险库版本的下发,每分钟刷新一次节点表。配置包带签名与版本号,客户端只接受版本号递增且签名有效的包,任何降级请求都会被拒绝——这条规则在 2026 年 8 月的一次配置回滚演练中被验证:旧版本包被正确拒绝,连接沿用内存中的上一份有效配置。
配置通道的三条规则
- 签名先行配置包由控制面私钥签名,客户端用内置公钥验签,验签失败直接丢弃。
- 版本单调只接受版本号大于当前值的包,杜绝把客户端回滚到存在已知问题的旧配置。
- 失败保留连续 3 次拉取失败后停止重试,沿用内存中的有效配置,避免退化为空策略。
控制面看不到什么
- 看不到正文 控制面与数据面物理分离,控制面不接入流量路径。
- 看不到目标 节点表只包含节点地址与权重,不含用户访问目标。
- 看不到密钥 密钥在客户端与节点之间协商,控制面不参与也不中转。
- 看得到健康度 节点延迟、丢包与在线会话数是控制面唯一可见的指标,均为聚合值。
控制面能看到聚合健康度,这属于运营必需数据,已列入字段表;它不是逐用户记录,无法用于还原任何单个会话。
故障、降级与误判
安全设计最容易失败的地方不是被攻破,而是在故障时悄悄退回明文。
快喵VPN 把故障处理分成三类:可恢复、需重连、必须阻断。分类标准是能否确认链路仍然加密——只要无法确认,就按必须阻断处理。2026 年 9 月的故障演练中,注入 6 类故障后,全部 6 类都没有出现明文出站,最长的服务中断为 4.2 秒。
故障分类与处理
| 故障类型 | 判定依据 | 处理动作 | 恢复耗时 | 是否阻断明文 |
|---|---|---|---|---|
| 节点无响应 | 心跳 3 次超时 | 自动切换备用节点 | 1.6 秒中位 | 是 |
| 证书指纹不符 | 握手阶段比对失败 | 中断连接并提示风险 | 需用户确认 | 是 |
| 配置拉取失败 | 连续 3 次失败 | 沿用旧配置,停止重试 | 不中断 | 否(仍加密) |
| 网卡异常 | 驱动返回错误 | 停止接管,恢复前阻断出站 | 2.4 秒中位 | 是 |
| 本地时间漂移 | 证书有效期判定失败 | 提示校时,暂停自动连接 | 需用户处理 | 是 |
| 隧道 MTU 不匹配 | 分片失败计数上升 | 自动探测并下调 MTU | 0.8 秒中位 | 否 |
误判与救济
任何自动判定都会误判。快喵给每条规则留了人工出口:诊断页可以导出事件摘要(含判定要素与时间戳,不含访问目标),用于申诉;误判被确认后会在下次风险库更新中调整阈值,并在更新记录中说明调整原因,而不是静默修改。
- 导出范围 事件摘要只包含风险要素、时间戳与动作,不含访问目标与会话密钥。
- 申诉通道 安全邮箱接受事件摘要与复现步骤,48 小时内给出处理结论。
- 阈值调整留痕 阈值变更进入更新记录,标注旧值、新值与触发原因。
附录:术语与参数
本节集中列出本章出现的边界术语与工程参数,便于与其他章节交叉比对。
关键数值与来源
下表把本页出现的数值与其采集条件并列列出,便于逐项核对。同一指标在不同条件下可能变化,引用时建议连同条件与样本量一起引用,否则数字会失真。
| 项目 | 数值与表述 | 采集条件与来源 |
|---|---|---|
| 握手额外耗时 | 握手阶段额外耗时中位 62 毫秒 | 条件:千兆宽带,2026-09 采样 200 次 |
| 单节点占用 | 每个活跃会话在接入节点占用约 210 KB 内存 | 来源:2026-09 受控测试采样,覆盖 3 个可用区 |
| 节点表刷新 | 控制面每 60 秒刷新一次节点表 | 依据:内部设计规范第 6 节 |
| 令牌有效期 | 短期会话令牌有效期 15 分钟,校验后立即丢弃 | 依据:内部设计规范第 5 节 |
| 演练中断时长 | 6 类故障注入后最长服务中断 4.2 秒 | 来源:2026-09-22 故障演练报告 |
| 明文出站次数 | 6 类故障场景下明文出站 0 次 | 条件:隔离环境,逐类注入并抓包 |
术语表
- 信任边界
- 密钥归属或拓扑可见性发生变化的位置,跨过边界即更换校验方式。
- 公钥固定
- 客户端预置节点证书指纹,只接受指纹匹配的连接,用于阻断伪造证书。
- 短期会话令牌
- 有效期 15 分钟的鉴权凭据,不携带账号明文,校验后立即丢弃。
- 节点表
- 控制面下发的节点地址与权重清单,每分钟刷新一次。
- 共享出口
- 多个会话共用同一出口地址的部署方式,用于削弱地址与账号的对应关系。
- 健康度
- 节点延迟、丢包与在线会话数的聚合指标,控制面唯一可见的运行数据。
- 配置包
- 带签名与版本号的下发单元,客户端只接受版本递增且验签通过的包。
- 故障注入
- 人为构造异常以验证降级行为的方法,本章表 4 即一次演练的结果。
参数汇总
| 参数 | 取值 | 适用环节 | 来源 |
|---|---|---|---|
| 握手密钥交换 | X25519 临时密钥 | 客户端与接入节点 | 设计文档第 4 节 |
| 令牌有效期 | 15 分钟 | 鉴权 | 设计文档第 5 节 |
| 节点表刷新 | 每 60 秒 | 控制面 | 设计文档第 6 节 |
| 单节点连接内存 | 约 210 KB | 接入节点 | 受控测试采样 |
| 单出口并发上限 | 480 个会话 | 出口层 | 节点侧配置 |
| 故障演练明文出站 | 0 次 | 6 类故障全覆盖 | 2026-09 演练记录 |
本章所有数值来自 V3.2 设计文档与 2026-09 故障演练记录,演练在隔离环境执行,不代表生产环境的全部故障组合。
部署自查与常见误区
架构图上的边界只有在实际部署中被守住才算数。本节给出可执行的核对顺序。
边界设计的失效往往不是被攻破,而是部署时被顺手打开了一个便利口:为排障关闭证书校验、为兼容老设备放宽协议版本、为降低延迟把 DNS 移回本地解析。这三类改动在日志里都表现为“配置正常”,因此需要一份独立的核对清单。
部署拓扑的三个约束
- 接入与出口分离 接入节点不承担出口职责,二者部署在不同可用区,避免单点同时持有两个角色。
- 控制面独立网段 控制面不与数据面共享网段,配置下发走独立通道,降低横向移动风险。
- 节点表动态下发 节点地址不写死在客户端,出现节点摘除时可下发更新,无需用户升级。
- 日志落点收敛 节点侧不落业务日志,仅在控制面保留聚合健康度,减少可被调阅的痕迹。
读者自查清单
- 查证书校验抓包确认握手阶段客户端会因指纹不符中断连接,而不是给出“继续”选项。
- 查降级路径在断网与节点无响应两种情况下观察是否有明文出站,这是最容易漏的一项。
- 查 DNS 归属确认 DNS 请求走隧道内解析,而不是本地解析后再送入隧道。
- 查配置签名尝试用旧版本配置包覆盖当前配置,应被版本单调规则拒绝。
- 查出口共享从两台设备同时访问同一站点,确认出口地址相同且无独立标识。
四类常见误区
| 误区 | 常见做法 | 问题所在 | 正确做法 | 观察指标 |
|---|---|---|---|---|
| 放宽协议版本 | 为兼容老系统允许 TLS 1.0 | 已知弱点重新暴露 | 最低 1.2,老系统单独提示 | 握手失败率上升 |
| 本地 DNS 优先 | 为降低延迟先本地解析 | 解析链路可被改写 | 隧道内解析,延迟可接受 | 解析延迟增加约 12 毫秒 |
| 关闭指纹校验 | 排障时临时关闭后忘记恢复 | 中间人风险长期存在 | 校验不可关闭,排障用旁路日志 | 事件日志出现校验跳过记录 |
| 固定节点地址 | 把节点 IP 写进客户端 | 节点摘除后无法更新 | 控制面动态下发 | 节点表刷新时间戳 |
上表第四行常被忽略:把节点地址写死看起来提高了可用性,实际会在节点被摘除时把用户困在一个失效地址上,而动态下发只需要一次 60 秒内的刷新就能恢复。这也是为什么快喵宁可多一条控制面通道,也不把节点表固化进安装包。
每一项自查都应记录观察位置、时间戳与结论三要素;只写“已检查”的结论无法被复核,也无法在版本变更后判断是否需要重做。