Buzz 的 NIP-AA 代理认证规范基于 NIP-OA 凭证与 NIP-42 的虚拟中继成员机制【免费下载链接】buzzA hive mind communication platform项目地址: https://gitcode.com/GitHub_Trending/buzz14/buzzNIP-AAAgent Authentication代理认证是本仓库中一份draft/optional/relay级别的 Nostr NIP 提案它定义了实现 NIP-43 成员制的中继relay应如何处理携带 NIP-OA 凭证的连接请求只要代理agent的所有者owner是活跃成员代理即可在 NIP-42 认证期间出示 NIP-OAauth标签获得隐式中继访问权而无需被显式加入成员列表。阅读本文后你将完整掌握 NIP-AA 的六步中继验证算法、虚拟成员virtual membership的权限边界、撤销语义与安全/隐私权衡并能在 buzz-relay 的源码中找到对应的实现证据。背景与动机成员制与代理授权的割裂NIP-43 定义了中继成员元数据强制成员制的中继将访问限制在一个显式成员列表内NIP-OAOwner Attestation见 docs/nips/NIP-OA.md则建立了所有者密钥授权某个代理密钥代表其行事的密码学事实。这两个 NIP 互为补充但彼此割裂管理员添加一位人类成员后还必须单独为该人类运行的每一个代理逐一办理入会。这种做法的摩擦与同步风险是显而易见的当某个成员的会员资格被撤销时其代理仍会留在成员列表中直到被手动清理当某位成员新建一个代理时该代理在管理员手动添加之前无法连接。NIP-AA 正是为了弥合这一缺口而设计代理在 NIP-42 认证时出示 NIP-OA 凭证中继验证凭证并检查所有者是否为活跃成员两者均通过则放行连接。若所有者后续被撤销会员资格代理的下一次连接尝试会自动失败——无需任何额外的清理工作。核心术语NIP-AA 全文遵循 RFC 2119 定义的 MUST、MUST NOT、SHOULD、SHOULD NOT、MAY 与 RECOMMENDED 语义关键概念如下owner key所有者密钥签发 NIP-OA 授权的 Nostr 密钥对所有者本身是 NIP-43 意义上的中继成员agent key代理密钥拥有自己 Nostr 密钥对的 AI 代理、机器人或自动化进程不必是中继成员auth标签NIP-OA 凭证标签[auth, owner-pubkey-hex, conditions, sig-hex]NIP-42 AUTH 事件客户端响应中继AUTH挑战而发送的kind:22242事件虚拟成员virtual membership从所有者成员资格派生的连接访问权不为代理创建任何持久化成员记录活跃成员active member中继权威访问控制状态中将其列为未撤销、当前有效且拥有显式成员记录的公钥。通过 NIP-AA 获得访问权的虚拟成员不是活跃成员NIP-43 的kind:13534事件可以通告或反映这一状态但其本身不是权威来源。协议流程NIP-AA 复用了标准的 NIP-42 握手代理在构造kind:22242事件时把 NIP-OAauth标签作为普通标签嵌入其中中继在完成 NIP-42 验证后执行 NIP-AA 附加检查。完整流程如下Agent Relay | | |-- [AUTH, challenge-string] ---| (NIP-42 step 1) | | | Build kind:22242 event: | | pubkey agent_pubkey | | tags [ | | [relay, wss://...], | | [challenge, nonce], | | [auth, owner-pubkey-hex, | | conditions, | | sig-hex] | | ] | | Sign with agent secret key | | | |---- [AUTH, kind:22242 event] --| (NIP-42 step 2) | | | Verify NIP-42 | | Check member list | | Verify auth tag | | Check owner member| | | |-- [OK, event-id, true, ] --| (access granted) | | | Subsequent events MAY carry auth | | tag per NIP-OA for provenance. | | NIP-AA membership is established | | by the AUTH event; the auth tag | | on subsequent events is not | | required for relay access. |这里有一个值得强调的设计点NIP-AA 的成员资格由 AUTH 事件本身确立后续事件是否携带auth标签按 NIP-OA 用于来源标注与中继访问权无关。失败时的响应规则验证失败时中继必须按下方验证算法中的错误前缀规则响应。若 AUTH 载荷损坏到无法解析出事件 id 的程度中继必须关闭 WebSocket 连接可先发送NOTICE消息。这是对 NIP-42AUTH 消息必须以 OK 应答要求的显式例外——没有可引用的事件 id该要求客观上无法满足。中继可以但非必须在任何 AUTH 失败时关闭 WebSocket一次独立的 AUTH 失败不会隐式使连接上先前已认证的身份失效。此规则不阻止中继出于其他原因例如所有者成员资格被撤销刻意重新验证或终止会话。中继验证算法六步顺序执行当收到 NIP-42 AUTH 事件kind:22242时中继必须按下述步骤按序执行。任何一步失败都意味着 AUTH 尝试被拒绝Step 1 失败事件畸形、id/sig无效、relay标签错误、created_at过期→ 响应[OK, event-id, false, invalid: reason]Step 3–5 失败缺少凭证、凭证无效、所有者非成员→ 响应[OK, event-id, false, restricted: reason]。一次失败的 NIP-AA AUTH 尝试不必然使同一 WebSocket 连接上其他已认证公钥失效。Step 1 —— 标准 NIP-42 验证按 NIP-42 验证 AUTH 事件event.kind必须为22242事件id与sig必须对event.pubkey有效relay标签必须与本中继的 URL 匹配challenge标签必须与本连接收到的 nonce 匹配。NIP-AA 额外要求AUTH 事件的created_at必须落在中继定义的新鲜度窗口内推荐 ±120 秒窗口外的 AUTH 事件必须拒绝。任何一项检查失败即拒绝。Step 2 —— 直接成员检查若event.pubkey本身就是活跃成员则按正常 NIP-43 流程放行后续步骤不再适用。Step 3 —— NIP-OA 凭证提取若event.pubkey不是活跃成员则在 AUTH 事件的标签中查找auth标签没有auth标签则拒绝多于一个auth标签则拒绝。Step 4 —— NIP-OA 凭证验证按 NIP-AA 专属流程验证auth标签。该流程复用了 NIP-OA 的密码学构造但并不等同于完整的 NIP-OA 验证——此处不评估kind子句详见下文 §Kind Conditions标签必须恰好包含四个元素owner-pubkey-hex必须是合法的 64 字符小写十六进制 BIP-340 公钥sig-hex必须是合法的 128 字符小写十六进制字符串owner-pubkey-hex不得等于event.pubkey禁止自认证conditions必须是语法合法的 NIP-OA 条件字符串见 NIP-OA §The Tag重建预映像preimagenostr:agent-auth:||event.pubkey||:||conditions其中conditions必须原样取自auth标签——实现不得在计算预映像前对条件做重排、去重、规范化或标准化计算SHA256(preimage)以owner-pubkey-hex为公钥将sig-hex作为对该 SHA256 哈希的 BIP-340 Schnorr 签名进行验证针对 AUTH 事件的created_at字段评估created_att与created_att子句不满足时间戳子句则拒绝。任何一项检查失败即拒绝。Step 5 —— 所有者成员检查在中继成员存储中查找owner-pubkey-hex若所有者不是活跃成员则拒绝。Step 6 —— 授予虚拟成员资格为成功 AUTH 事件中event.pubkey对应的公钥授予虚拟成员资格不得为代理创建持久化成员记录。中继必须在连接的整个生命周期内于虚拟会话状态中保留验证通过的owner-pubkey-hex以支撑按所有者维度进行的会话枚举、终止与配额聚合。代理的访问是虚拟的从所有者的成员资格派生而来并且作用于特定公钥而非整个 WebSocket 连接若连接上存在多个已认证公钥符合 NIP-42虚拟成员资格仅适用于完成 NIP-AA 认证的那个公钥。若同一代理公钥在同一连接上再次完成 NIP-AA 认证例如携带不同的auth凭证中继必须用新凭证替换此前存储的凭证不得将多次 AUTH 事件的凭证合并使用。Kind Conditions连接准入与逐事件执行的区分凭证中的kind子句不会在连接准入时被评估也不影响中继是否放行。它是所有者意图的声明——说明所有者打算授权哪些事件类型——但中继的强制力在连接层面。凭证范围警告在 NIP-42 认证期间出示的auth标签无论其中kind子句如何都会授予连接级访问权。所有者应当意识到签发任何有效的auth标签即使带有窄kind条件都会赋予代理完整的中继读写访问权除非中继实现了可选的逐事件强制。希望把代理限制到特定事件类型的所有者必须确保中继执行逐事件kind限制不应仅依赖kind子句做访问控制为事件来源标注目的如kind1签发的凭证一旦用于 NIP-AA 就变成了中继登录凭证这种语义扩展是有意为之。若中继执行kind限制则必须在整个连接期间保留 AUTH 事件中验证过的凭证并对event.pubkey匹配该虚拟成员公钥的每个事件在接收、存储或转发前评估该凭证中的每一条kind子句。逐事件强制仅针对kind子句created_at与created_at子句在连接准入Step 4时已评估不会对后续事件重复评估。当逐事件强制拒绝一个EVENT时中继必须响应[OK, event-id, false, restricted: reason]。合取语义按 NIP-OA单一凭证中的多个kind子句是合取关系——事件必须满足每一条子句。条件为kind1kind7的凭证不会授权任何单个事件因为没有任何事件能同时具有两个不同的kind值。所有者应当为每个凭证使用单一kind子句要授权多种事件类型要么在各自独立的连接上使用独立凭证NIP-AA 每个 AUTH 事件只接受一个auth标签要么使用不含kind子句的无约束凭证。虚拟成员权限获得 NIP-AA 虚拟成员资格的代理可以通过中继级成员检查包括读订阅 REQ与写事件发布 EVENT访问。但以下检查必须继续以代理自身公钥event.pubkey为准除非其他规范显式定义了所有者继承频道级、群组级、配额与角色检查NIP-AA不授予代理所有者的频道成员资格、群组角色或管理权限。具体规则如下对EVENT提交中继必须验证event.pubkey是该连接上持有活跃或虚拟成员资格的已认证公钥来自未认证或非成员公钥的事件必须拒绝对REQ、COUNT及其他非EVENT操作只要连接上至少一个已认证公钥持有活跃或虚拟成员资格中继级访问即通过但频道级、群组级与资源级访问检查必须评估持有虚拟成员资格的那个公钥而非所有者公钥当同一连接上认证了多个公钥时中继不得合并它们的权限每个公钥的访问独立评估资源级操作只有在至少一个已认证公钥独立满足该操作所需的全部中继级与资源级检查时才通过。配额与速率限制中继 SHOULD 在按代理公钥强制之外额外按所有者公钥在所有源自该所有者的虚拟成员之间聚合速率限制与配额。否则单个成员可以铸造大量代理密钥来成倍突破按公钥的配额。管理边界虚拟成员必须不得被授予中继管理权限具体机制实现自定例如分配一个排除管理操作的受限角色或在处理管理命令前检查虚拟成员状态虚拟成员必须不得被允许修改中继成员资格添加或移除成员实现 SHOULD 在中继审计日志与成员内省 API 中把虚拟成员明确标识出来。撤销语义虚拟成员资格在每次新连接时检查不会跨重连缓存。所有者移除当所有者成员资格被撤销所有访问权源自该所有者的代理其下一次连接尝试都会在 Step 5 失败。已活跃的会话不会被强制终止而是持续到底层 WebSocket 连接关闭。需要立即终止会话的运维人员应在撤销成员时主动断开活跃 WebSocket 连接中继 SHOULD 暴露按所有者公钥枚举与终止会话的机制auth标签过期若auth标签条件含created_att子句中继在连接时Step 4以 AUTH 事件的created_at字段评估它——这约束的是 AUTH 事件自我声明的created_at字段。只有与中继强制的 AUTH 事件新鲜度Step 1结合才能提供有界的授权窗口。条件评估只发生在连接准入Step 4除非实现显式的会话重新验证否则中继不会在活跃会话期间重新评估条件注意created_at由代理控制。恶意代理可以把created_at设为任意值。需要硬性墙钟过期的运维人员必须独立强制。签发带短created_at窗口并轮换的auth标签之所以能提供有界授权正是因为 Step 1 要求 AUTH 事件的created_at落在中继新鲜度窗口内——从而阻止代理把时间回拨以绕过已过期的条件。代理密钥泄露持有有效auth标签的代理只要所有者仍是活跃成员且标签中created_at条件满足即可持续重连。撤销只能通过三种方式之一实现(a) 从成员列表移除所有者(b)auth标签的created_at条件过期(c) 中继应用独立的拒绝名单。NIP-OA 凭证是可复用能力——在没有上述机制之一的情况下所有者无法单方面撤销已签发的auth标签。安全考虑重放防护NIP-42 AUTH 事件绑定到特定中继挑战 nonce无法跨会话重放。其中的 NIP-OAauth标签是可复用凭证——任何持有代理私钥的人都可以构造携带同一auth标签的新 AUTH 事件。这是刻意设计NIP-OA 凭证是能力capability而非一次性令牌。实现必须强制 NIP-42 挑战新鲜度由于 NIP-AA 的重放防护完全依赖 NIP-42 的挑战质量实现 NIP-AA 的中继 SHOULD 使用密码学上不可预测、连接唯一的挑战字符串凭证范围auth标签不绑定特定中继或用途。连接多个中继的代理会在每个中继出示同一auth标签为事件来源标注签发的凭证与用于 NIP-AA 中继准入同样有效。运维人员 SHOULD 在适当场合使用created_at条件限制授权窗口所有者密钥暴露所有者公钥在 AUTH 事件的auth标签中可见这把所有者与代理的身份关联暴露给了处理该连接的中继见隐私考虑自认证owner-pubkey-hex等于event.pubkey的auth标签必须拒绝Step 4防止代理通过签署自己的凭证来引导自身访问权伪造凭证中继在 Step 4 验证 Schnorr 签名。伪造的auth标签签名错误无法通过密码学验证由非成员所有者签名的auth标签无法通过 Step 5。两种攻击都不会获得访问权kind过宽由于kind条件不在连接层强制带kind1条件的凭证与无约束凭证授予同样的连接级访问权。需要 kind 级限制的运维人员必须实现可选的逐事件强制见 §Kind Conditions。隐私考虑在 NIP-42 认证期间出示auth标签会向中继披露所有者-代理关系中继得知owner-pubkey-hex授权了event.pubkey代理。这是有意披露——中继需要该信息执行成员检查。中继 SHOULD NOT 向其他成员暴露超出虚拟成员识别必要范围的所有者-代理关系不需要通过 NIP-AA 获取中继访问权的代理可以在 AUTH 事件中省略auth标签、改用显式成员注册从而避免这种披露。验证示例以下示例使用 NIP-OA 测试密钥owner_secret 0000000000000000000000000000000000000000000000000000000000000001 owner_pubkey 79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 agent_secret 0000000000000000000000000000000000000000000000000000000000000002 agent_pubkey c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5NIP-OAauth标签取自 NIP-OA 测试向量条件为kind1created_at1713957000[auth, 79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798, kind1created_at1713957000, 8b7df2575caf0a108374f8471722b233c53f9ff827a8b0f91861966c3b9dd5cb2e189eae9f49d72187674c2f5bd244145e10ff86c9f257ffe65a1ee5f108b369]该标签的密码学验证预映像、SHA256 与签名由 NIP-OA 测试向量覆盖。以下示例描述的是各种场景下中继的预期行为在没有完整 NIP-42 事件id与sig的情况下它们无法独立复验。接受场景携带有效 NIP-OA 凭证连接的代理条件owner_pubkey是活跃中继成员AUTH 事件created_at 1713956400中继墙钟时间接近1713956400落在 ±120 秒新鲜度窗口内created_at1713957000条件满足。Step 1NIP-42 验证通过created_at在新鲜度窗口内Step 2agent_pubkey不在成员存储中 → 继续Step 3恰好找到一个auth标签 → 继续Step 4标签有四个元素owner_pubkey合法owner_pubkey≠agent_pubkey条件字符串语法合法Schnorr 签名验证通过created_at1713957000被1713956400满足 → 通过Step 5owner_pubkey是活跃成员 → 通过Step 6代理公钥获得虚拟成员资格。拒绝场景一览中继必须拒绝以下每种情况场景失败步骤auth标签签名无效错误的 owner keyStep 4auth标签owner-pubkey-hex等于event.pubkeyStep 4auth标签元素数少于或多于四个Step 4auth标签conditions畸形如kind01Step 4AUTH 事件created_at为1713957001且条件为created_at1713957000Step 4AUTH 事件created_at超出中继新鲜度窗口Step 1owner_pubkey不是活跃中继成员Step 5AUTH 事件有两个auth标签Step 3AUTH 事件无auth标签且agent_pubkey非成员Step 3虚拟成员提交中继成员管理命令如添加/移除成员虚拟成员权限准入后kind 强制示例以下示例说明可选的逐事件kind强制行为所用凭证条件为kind1created_at1713957000场景强制启用结果虚拟成员发布kind:1否接受虚拟成员发布kind:7否接受仅连接级访问虚拟成员发布kind:1是接受满足kind1子句虚拟成员发布kind:7是拒绝kind7不在凭证中与其他 NIP 的关系NIP-42NIP-AA 扩展了 NIP-42 AUTH 流程kind:22242事件是凭证呈现载体。NIP-AA不新增任何事件类型NIP-OANIP-AA 在中继连接层消费 NIP-OA 凭证。NIP-OA 定义了auth标签格式、签名预映像与条件语法NIP-AA 定义了中继在 NIP-42 认证期间如何处理该标签。NIP-AA 的 Step 4 复用了 NIP-OA 的密码学构造但选择性应用kind子句不在连接准入时评估。这是对 NIP-OA验证者必须评估每条子句规则的刻意偏离——该规则适用于事件级验证而非连接准入NIP-43NIP-AA 是 NIP-43中继访问元数据与请求的扩展。未实现 NIP-43 的中继没有成员概念SHOULD NOT 实现 NIP-AA实现 NIP-43 的中继 MAY非必须实现 NIP-AANIP-26NIP-OA 复用了 NIP-26 的凭证格式但未复用其语义NIP-AA 继承了这一区分。auth标签不得被解释为 NIP-26 委托代理始终是其事件的唯一作者。仓库中的工程化实现上述规范在本仓库的 buzz-relay 与 buzz-sdk 中已有落地实现可作为 NIP-AA 的参考实现来对照研读NIP-42 AUTH 处理器crates/buzz-relay/src/handlers/auth.rshandle_auth在完成纯密码学 NIP-42 验证后依次通过社区封禁闸门、公钥白名单闸门与enforce_relay_membership成员闸门。其中extract_auth_tag_json从签名事件中提取 NIP-OAauth标签——注释明确指出该标签受事件 Schnorr 签名完整性保护一旦被篡改NIP-42 验证会在检查它之前失败。文件末尾的单元测试覆盖了单个auth标签原样提取无标签返回 None重复标签返回 Nonefail-closed三种情形成员决策枚举与检查crates/buzz-relay/src/api/mod.rsrelay_members模块定义了MembershipDecision枚举OpenRelay/Member/ViaOwner(nostr::PublicKey)/Deniedcheck_relay_membership在require_relay_membership开启时先查代理自身是否为成员非成员时在allow_nip_oa_auth开启的前提下调用buzz_sdk::nip_oa::verify_auth_tag_for_auth_event验证凭证再查所有者是否为成员并返回ViaOwner——这与 NIP-AA 的 Step 2/3/4/5 一一对应NIP-OA 密码学实现crates/buzz-sdk/src/nip_oa.rs实现nostr:agent-auth:预映像构造、SHA256消息哈希与 BIP-340 Schnorr 签名验证并严格校验条件字符串语法无空白、无空子句、无前导零、kind取值范围 0–65535、created_at取值范围 0–4294967295配置开关crates/buzz-relay/src/config.rsBUZZ_REQUIRE_RELAY_MEMBERSHIP与BUZZ_ALLOW_NIP_OA_AUTH均默认false控制成员制与 NIP-OA 委托准入。前者为 true 且后者为 true 时携带有效 NIP-OAauth标签的代理可证明其所有者是中继成员从而获得会话级访问在开放中继上NIP-OA 所有者提取用于 agent→owner 反向回填无条件进行因为签名是密码学自证的该开关只控制封闭中继上 NIP-OA 能否授予成员访问权。这与 NIP-AA 的实现 NIP-43 的中继 MAY 实现 NIP-AA的定位完全吻合。小结NIP-AA 用一个精炼的六步验证算法把 NIP-43 的成员制、NIP-OA 的所有者授权凭证与 NIP-42 的认证通道缝合在一起代理凭一张auth标签即可在所有者名下的中继获得虚拟成员资格所有者的撤销自动传导到代理的下一次连接且代理的权限被严格限制在连接级虚拟访问无法继承所有者的频道、角色、配额与管理特权。对于运行 Agent 生态的中继运维者而言理解 Step 4 与 Step 6 的语义边界、kind条件的连接级/事件级双重语义以及created_at自声明与中继新鲜度窗口的组合作用是安全落地本规范的关键。【免费下载链接】buzzA hive mind communication platform项目地址: https://gitcode.com/GitHub_Trending/buzz14/buzz创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
