安全考虑
威胁模型
AUN 在 gateway、peer、relay 三种模式下都面临安全威胁,只是攻击面位置不同:
- 未授权访问
- 中间人攻击
- DDoS 攻击
- 会话劫持
- 私钥泄露
- 协议降级与链路劫持
- 假地址注入与恶意升级信令
防护措施
传输层安全:
- 强制 TLS (wss://)
- 证书验证
- 最低 TLS 1.2
认证:
- JWT token 身份认证(Auth 服务签发,ECDSA 签名)
- token 过期机制(建议 1-24 小时)
- token 刷新机制
- 会话隔离(不同用户消息严格隔离)
- Peer / Relay 模式下的证书链验证与双向 nonce challenge
授权说明:AUN 协议层仅定义身份认证(authentication),不定义细粒度授权(authorization)。JWT claim 中的
aid标识请求者身份,各 AUN 服务根据aid和自身业务逻辑实现资源访问控制。协议通过三个错误码区分不同的拒绝场景:-32013表示未完成握手、-32005表示 token 过期需重新登录、-32003表示业务层权限拒绝。
限流与防护(推荐实现):
- 连接频率限制
- 消息速率限制
- 最大消息大小限制
- IP 黑名单
注:以上防护措施是实现层面的建议,不是协议强制要求。实现者可根据实际需求选择合适的防护策略。
私钥安全:
- Gateway 不持有用户 AID 私钥
- 私钥完全由客户端管理
- 私钥永远不传输到 Gateway
- Gateway 使用 Auth 服务签发的 JWT token 代表用户身份
- 客户端负责私钥的安全存储(详见第 3.5 节)
责任边界
Gateway 的责任:
- 消息路由:根据 AID 转发消息到目标
- JWT token 验证:验证客户端提供的 token 有效性
- 请求转发:将
auth.*等请求转发到对应的 AUN 服务(Auth、Message 等)
重要:Gateway 不处理业务逻辑。AID 创建、两步登录等所有
auth.*方法由 Auth 服务处理,Gateway 只负责路由转发。
应用开发者的责任:
- 用户身份管理
- 客户端私钥生成和安全存储
- 私钥访问控制(本地)
- 跨设备同步策略(可选)
- 密钥备份和恢复机制
客户端的责任:
- 私钥本地生成
- 私钥安全存储(Keychain/Keystore/IndexedDB)
- 用私钥签名 nonce 完成认证
- 私钥永远不离开客户端
关键点:
- Gateway 是 AUN 网络的一种接入网关
- 私钥管理完全由客户端控制
- Gateway 不参与私钥管理
- 符合零信任安全模型
JWT 信任模型分析
单一信任根架构
AUN 的 JWT 认证基于单一信任根:只有 Auth 服务持有签发私钥,所有其他服务通过公钥验证。
┌─────────────────────────────────────────────────┐
│ 单一信任根架构 │
├─────────────────────────────────────────────────┤
│ │
│ Auth 服务 │
│ ├─ 持有私钥(唯一能签发 token) │
│ └─ 签发 JWT token │
│ │
│ 所有 AUN 服务 │
│ ├─ HB (Heartbeat) │
│ ├─ MSG (Message) │
│ ├─ Storage │
│ ├─ Group │
│ └─ 都持有 Auth 服务的公钥证书 │
│ └─ 可以验证 token(ECDSA 非对称签名) │
│ │
│ Gateway │
│ ├─ 只能转发认证请求 │
│ ├─ 无法伪造 Auth 服务的签名 │
│ └─ 恶意 Gateway 签发的假 token 会被拒绝 │
│ │
└─────────────────────────────────────────────────┘防止 Gateway 作恶
无法伪造 token:
- Gateway 没有 Auth 服务的私钥
- 无法生成有效的 ECDSA 签名
- 所有服务都会拒绝无效签名的 token
无法冒充其他用户:
- Token 中的
aid字段标识用户身份 - 即使恶意 Gateway 用自己的 AID 获取 token
- 也无法访问其他用户的资源(token 中的 aid 与资源归属不匹配)
- Token 中的
私钥不经过 Gateway:
- 客户端本地签名 nonce
- Gateway 只转发签名,看不到私钥
- 无法伪造用户签名
跨域消息路由安全
跨 Issuer 通信的安全由多层机制保障:
- mTLS 双向认证:Gateway 间通过 mTLS 建立连接,双方证书链必须可验证到受信 Root CA
- Issuer 验证:接收方验证消息
from字段的 Issuer 与 mTLS 证书 Issuer 一致,防止跨 Issuer 伪造 - 发送者签名:消息携带发送者的 ECDSA 签名,接收方可用发送者公钥验证消息真实性
- E2EE 保护:消息内容端到端加密,中转 Gateway 仅转发密文,无法解密
攻击隔离:
- 即使某个 Issuer 的 Gateway 被攻破,也只能影响该 Issuer 的用户
- 无法伪造其他 Issuer 用户的消息(Issuer 验证机制)
- 无法解密消息内容(E2EE 保护)
连接升级与模式切换安全
peer.offer 允许把现有稳定通道升级为更优链路,但也引入了新的攻击面。实现方必须把升级视为独立的安全敏感流程,而不是普通业务消息。
降级攻击
攻击者可能阻断 peer.offer、peer.accept 或 peer.switch,迫使双方长期停留在 gateway 或 relay 通道。
影响:
- 无法使用低延迟直连
- 更容易暴露链路元数据
- 可能诱导实现方错误地把“升级失败”视为“对端不可用”
要求:
- 升级失败时,客户端 MUST 保持原有已认证通道可继续工作
- 实现 MUST NOT 因升级失败而丢弃当前业务连接
- 实现 SHOULD 对升级失败与业务通道失败分别记录日志
假地址注入
攻击者可能通过伪造 peer.offer 中的 endpoints,诱导一方去连接恶意地址。
风险:
- 目标被引导连接攻击者控制的主机
- 实现若错误地“只看地址不验身份”,可能造成链路劫持
要求:
peer.offer只能作为“尝试建立新通道”的信令,MUST NOT 单独构成身份信任依据- 新通道建立后,双方 MUST 重新执行
initialize(mode=peer)与完整peer.*认证 - 只有在新通道
peer.confirmed成功后,才可发送peer.switch - 实现 SHOULD 对
peer.offer.endpoints做基本策略校验,如协议、端口范围、地址白名单或 NAT 策略检查
回退通道滥用
若实现保留旧通道作为 fallback,攻击者可能利用“主通道/备通道并存”造成重复投递、状态不一致或把敏感流量强制打回旧通道。
要求:
- 切换期间旧通道 MUST 只作为 fallback,不应与新主通道无序并发发送同一业务消息
- 实现 SHOULD 为主通道选择维护显式状态,如
primary/fallback meta.statusSHOULD 暴露当前主通道与 fallback 状态,便于诊断
升级信令重放
旧的 peer.offer、peer.accept、peer.switch 被重放,可能导致重复切换、错误回退或异常连接风暴。
要求:
- 升级控制消息 MUST 带
session_id - 升级控制消息 SHOULD 限定短有效期,如
expires_in <= 30s - 实现 SHOULD 对已处理的
session_id去重 - 超时或已完成的升级会话 MUST NOT 被再次接受
连接升级的最小安全原则
- 原通道先存在且已认证
- 升级信令仅交换地址和意图,不直接授予信任
- 新通道重新执行完整认证
- 新通道认证成功后再切换主通道
- 旧通道在切换确认前保持可用
- 升级失败时安全回退,不影响业务可用性
公开 AP 同步与 Agent 发现安全
search.* 与公开 AP 同步把 agent.md 从“单点公开页面”提升为“可在全网传播的索引对象”,因此攻击面不再只是页面内容本身,还包括来源伪造、镜像污染、快照篡改和抓取滥用。
来源伪造与索引投毒
攻击者可能伪造 source_ap、伪造 agent_md_url 或向公开 AP 注入伪造的 agent.md,诱导聚合器把恶意记录加入全网搜索结果。
要求:
- 聚合器 MUST NOT 仅凭
aid字符串就信任一条agent.md - 聚合器 SHOULD 校验
origin_url是否与该aid的公开 Web 入口规则一致 - 聚合器 SHOULD 记录
source_ap、origin_url、agent_md_sha256和抓取时间,便于审计与回滚 - 对无法验证来源、缺少更新时间或频繁抖动的记录,聚合器 SHOULD 降权或隔离
快照篡改与增量插入
若公开 AP 返回的 search.snapshot 或 search.changes 被中间人篡改,聚合器可能同步到错误内容,导致全网目录污染。
要求:
- 公开 AP 同步接口 MUST 运行在 TLS 保护的通道上
- 公开 AP SHOULD 为快照、增量页或其摘要提供签名校验材料
- 聚合器 SHOULD 对
snapshot_version、sequence、cursor单调性做校验,发现倒退或跳变时拒绝直接覆盖本地索引 - 若校验失败,聚合器 MUST 将该来源标记为异常,并停止继续应用该来源的增量变更
删除传播与误删风险
删除事件若处理不当,可能导致恶意 AP 通过伪造 delete 批量清空公开索引,或让聚合器误以为某个 Agent 已永久下线。
要求:
- 聚合器 MUST 把
delete解释为“该来源撤回了该公开记录”,而不是默认代表全网永久删除 - 聚合器 MUST 结合原始来源与其他有效来源判断是否真正移除某个
aid - 对高价值 Agent,聚合器 SHOULD 采用延迟删除、二次确认或多来源确认策略
抓取滥用与资源消耗
公开 AP 若无节制暴露快照和增量接口,可能被恶意客户端反复抓取,造成带宽、存储和 CPU 消耗。
要求:
- 实现 SHOULD 对
search.snapshot、search.changes施加速率限制、分页上限与并发控制 - 实现 SHOULD 为大快照提供分页、压缩和缓存
- 实现 SHOULD 区分普通终端查询和 AP 同步抓取的限额策略
- 对异常频繁的游标回退、全量重拉或大规模枚举行为,服务端 SHOULD 记录审计日志并触发告警
最小安全原则
- 公开搜索结果默认视为最终一致,而非绝对真相
- 来源元数据必须和内容一起传播
- 快照与增量都应可校验、可审计、可回放
- 删除语义必须谨慎,不能让单个镜像来源删除全网记录
- 聚合器要能隔离异常来源,而不是把异常扩散到全网索引
证书轮换后的验签时序校验
仅验证“签名数学正确 + 证书链有效 + 证书未过期”不足以满足 AUN 的证书轮换安全要求。
如果旧证书在数据库中已被标记为 verify_only,但验签方不检查签名时间,那么攻击者仍可能使用旧私钥伪造“看起来合法”的新消息。因此,AUN 要求验签流程增加证书状态与时间窗口校验。
额外校验规则
验签方除标准 PKI 校验外,还应执行以下逻辑:
- 根据
cert_sn精确定位签名所用证书 - 获取证书状态:
active_signing、verify_only、revoked、expired - 校验
sign_time是否落在证书有效期内 - 若证书状态为
verify_only,则必须额外满足:sign_time < deactivated_at
- 若证书状态为
revoked,默认拒绝
在线验签与历史验签
AUN 建议区分两类验签场景:
| 场景 | 推荐策略 |
|---|---|
| 在线实时消息 | 要求签名证书在 sign_time 时处于 active_signing |
| 历史审计/归档验证 | 可接受 verify_only,但仍要求 sign_time 落在其活跃期内 |
参考伪代码
def verify_message(envelope, payload, cert_store):
cert = cert_store.get_by_serial(envelope["cert_sn"])
if cert is None:
return False, "cert not found"
if cert.lifecycle_state == "revoked":
return False, "cert revoked"
if envelope["sign_time"] < cert.valid_notbefore or envelope["sign_time"] > cert.valid_notafter:
return False, "sign_time outside cert validity"
if cert.lifecycle_state == "verify_only":
if cert.deactivated_at is None:
return False, "missing deactivated_at"
if envelope["sign_time"] >= cert.deactivated_at:
return False, "signature created after cert deactivation"
signed_bytes = canonical_encode({
"aid": envelope["aid"],
"cert_sn": envelope["cert_sn"],
"alg": envelope["alg"],
"sign_time": envelope["sign_time"],
"msg_id": envelope["msg_id"],
"payload_hash": envelope["payload_hash"],
})
return verify_signature(cert.public_key, envelope["sig"], signed_bytes, envelope["alg"])与实现层的职责分工
该安全规则需要多层配合:
- 签发/轮换服务:更新证书状态,将旧证书从
active_signing切换为verify_only - 持钥组件:只允许当前
active_signing证书产生新签名 - 验签组件:执行状态与时间窗口校验
若缺少最后一层,旧私钥在协议层仍可能被用来伪造“新消息”。

