Skip to content

安全考虑

威胁模型

AUN 在 gatewaypeerrelay 三种模式下都面临安全威胁,只是攻击面位置不同:

  • 未授权访问
  • 中间人攻击
  • 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 作恶

  1. 无法伪造 token

    • Gateway 没有 Auth 服务的私钥
    • 无法生成有效的 ECDSA 签名
    • 所有服务都会拒绝无效签名的 token
  2. 无法冒充其他用户

    • Token 中的 aid 字段标识用户身份
    • 即使恶意 Gateway 用自己的 AID 获取 token
    • 也无法访问其他用户的资源(token 中的 aid 与资源归属不匹配)
  3. 私钥不经过 Gateway

    • 客户端本地签名 nonce
    • Gateway 只转发签名,看不到私钥
    • 无法伪造用户签名

跨域消息路由安全

跨 Issuer 通信的安全由多层机制保障:

  1. mTLS 双向认证:Gateway 间通过 mTLS 建立连接,双方证书链必须可验证到受信 Root CA
  2. Issuer 验证:接收方验证消息 from 字段的 Issuer 与 mTLS 证书 Issuer 一致,防止跨 Issuer 伪造
  3. 发送者签名:消息携带发送者的 ECDSA 签名,接收方可用发送者公钥验证消息真实性
  4. E2EE 保护:消息内容端到端加密,中转 Gateway 仅转发密文,无法解密

攻击隔离

  • 即使某个 Issuer 的 Gateway 被攻破,也只能影响该 Issuer 的用户
  • 无法伪造其他 Issuer 用户的消息(Issuer 验证机制)
  • 无法解密消息内容(E2EE 保护)

连接升级与模式切换安全

peer.offer 允许把现有稳定通道升级为更优链路,但也引入了新的攻击面。实现方必须把升级视为独立的安全敏感流程,而不是普通业务消息。

降级攻击

攻击者可能阻断 peer.offerpeer.acceptpeer.switch,迫使双方长期停留在 gatewayrelay 通道。

影响

  • 无法使用低延迟直连
  • 更容易暴露链路元数据
  • 可能诱导实现方错误地把“升级失败”视为“对端不可用”

要求

  • 升级失败时,客户端 MUST 保持原有已认证通道可继续工作
  • 实现 MUST NOT 因升级失败而丢弃当前业务连接
  • 实现 SHOULD 对升级失败与业务通道失败分别记录日志

假地址注入

攻击者可能通过伪造 peer.offer 中的 endpoints,诱导一方去连接恶意地址。

风险

  • 目标被引导连接攻击者控制的主机
  • 实现若错误地“只看地址不验身份”,可能造成链路劫持

要求

  • peer.offer 只能作为“尝试建立新通道”的信令,MUST NOT 单独构成身份信任依据
  • 新通道建立后,双方 MUST 重新执行 initialize(mode=peer) 与完整 peer.* 认证
  • 只有在新通道 peer.confirmed 成功后,才可发送 peer.switch
  • 实现 SHOULDpeer.offer.endpoints 做基本策略校验,如协议、端口范围、地址白名单或 NAT 策略检查

回退通道滥用

若实现保留旧通道作为 fallback,攻击者可能利用“主通道/备通道并存”造成重复投递、状态不一致或把敏感流量强制打回旧通道。

要求

  • 切换期间旧通道 MUST 只作为 fallback,不应与新主通道无序并发发送同一业务消息
  • 实现 SHOULD 为主通道选择维护显式状态,如 primary / fallback
  • meta.status SHOULD 暴露当前主通道与 fallback 状态,便于诊断

升级信令重放

旧的 peer.offerpeer.acceptpeer.switch 被重放,可能导致重复切换、错误回退或异常连接风暴。

要求

  • 升级控制消息 MUSTsession_id
  • 升级控制消息 SHOULD 限定短有效期,如 expires_in <= 30s
  • 实现 SHOULD 对已处理的 session_id 去重
  • 超时或已完成的升级会话 MUST NOT 被再次接受

连接升级的最小安全原则

  1. 原通道先存在且已认证
  2. 升级信令仅交换地址和意图,不直接授予信任
  3. 新通道重新执行完整认证
  4. 新通道认证成功后再切换主通道
  5. 旧通道在切换确认前保持可用
  6. 升级失败时安全回退,不影响业务可用性

公开 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_aporigin_urlagent_md_sha256 和抓取时间,便于审计与回滚
  • 对无法验证来源、缺少更新时间或频繁抖动的记录,聚合器 SHOULD 降权或隔离

快照篡改与增量插入

若公开 AP 返回的 search.snapshotsearch.changes 被中间人篡改,聚合器可能同步到错误内容,导致全网目录污染。

要求

  • 公开 AP 同步接口 MUST 运行在 TLS 保护的通道上
  • 公开 AP SHOULD 为快照、增量页或其摘要提供签名校验材料
  • 聚合器 SHOULDsnapshot_versionsequencecursor 单调性做校验,发现倒退或跳变时拒绝直接覆盖本地索引
  • 若校验失败,聚合器 MUST 将该来源标记为异常,并停止继续应用该来源的增量变更

删除传播与误删风险

删除事件若处理不当,可能导致恶意 AP 通过伪造 delete 批量清空公开索引,或让聚合器误以为某个 Agent 已永久下线。

要求

  • 聚合器 MUSTdelete 解释为“该来源撤回了该公开记录”,而不是默认代表全网永久删除
  • 聚合器 MUST 结合原始来源与其他有效来源判断是否真正移除某个 aid
  • 对高价值 Agent,聚合器 SHOULD 采用延迟删除、二次确认或多来源确认策略

抓取滥用与资源消耗

公开 AP 若无节制暴露快照和增量接口,可能被恶意客户端反复抓取,造成带宽、存储和 CPU 消耗。

要求

  • 实现 SHOULDsearch.snapshotsearch.changes 施加速率限制、分页上限与并发控制
  • 实现 SHOULD 为大快照提供分页、压缩和缓存
  • 实现 SHOULD 区分普通终端查询和 AP 同步抓取的限额策略
  • 对异常频繁的游标回退、全量重拉或大规模枚举行为,服务端 SHOULD 记录审计日志并触发告警

最小安全原则

  1. 公开搜索结果默认视为最终一致,而非绝对真相
  2. 来源元数据必须和内容一起传播
  3. 快照与增量都应可校验、可审计、可回放
  4. 删除语义必须谨慎,不能让单个镜像来源删除全网记录
  5. 聚合器要能隔离异常来源,而不是把异常扩散到全网索引

证书轮换后的验签时序校验

仅验证“签名数学正确 + 证书链有效 + 证书未过期”不足以满足 AUN 的证书轮换安全要求。

如果旧证书在数据库中已被标记为 verify_only,但验签方不检查签名时间,那么攻击者仍可能使用旧私钥伪造“看起来合法”的新消息。因此,AUN 要求验签流程增加证书状态与时间窗口校验。

额外校验规则

验签方除标准 PKI 校验外,还应执行以下逻辑:

  1. 根据 cert_sn 精确定位签名所用证书
  2. 获取证书状态:active_signingverify_onlyrevokedexpired
  3. 校验 sign_time 是否落在证书有效期内
  4. 若证书状态为 verify_only,则必须额外满足:
    • sign_time < deactivated_at
  5. 若证书状态为 revoked,默认拒绝

在线验签与历史验签

AUN 建议区分两类验签场景:

场景推荐策略
在线实时消息要求签名证书在 sign_time 时处于 active_signing
历史审计/归档验证可接受 verify_only,但仍要求 sign_time 落在其活跃期内

参考伪代码

python
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 证书产生新签名
  • 验签组件:执行状态与时间窗口校验

若缺少最后一层,旧私钥在协议层仍可能被用来伪造“新消息”。


AUN Protocol Documentation