摘要
- 读取 JMAP 会话信息与创建推送订阅之间若发生密钥轮换,验证可能因新旧密钥不匹配而被拒绝。服务器不得重试这次被拒绝的验证,客户端必须检查响应中的会话状态。
- RFC 9749 关于“最后一次通知”的可选安排受到一条技术勘误质疑。截至查阅时,勘误仍为已报告状态,不能把它当作已经生效的修订,也不能继续把争议通知链当成可靠保障。
“再等等,服务器应该会重发。”这句话放在许多远程操作里并不奇怪。危险在于,它有时只是经验,而不是当前协议承诺。
设想一次 JMAP 推送订阅创建:客户端收到了接口响应,却始终没有等到完成验证所需的消息。后台的密钥轮换任务已经结束,订阅创建也有记录。两个局部动作都可以在各自的看板上变绿,用户端的通知通道却未必已经可用。
这是依据标准构造的工作场景,不是对某家服务商事故的报道。RFC 9749 对其中一种竞争情况给出了很具体的要求:验证因为密钥失配而被推送服务拒绝后,JMAP 服务器不得重试该次 PushVerification。客户端需要从返回的 sessionState 检查自己的密钥假设是否仍然成立。若所有人都在等发送端自动补救,恢复工作就可能没有接手者。
新旧两份信息,不能靠一个“成功”合并
RFC 9749 于 2025 年 3 月发布,为 JMAP Web Push 引入 VAPID 身份认证。客户端通过 Session 对象获知应用服务器公钥,再据此建立受该公钥约束的推送订阅。这两个动作之间有时间间隔,并不是一个原子操作。
如果客户端刚读完旧公钥,服务器就轮换了密钥,随后发出的订阅验证便可能携带新密钥的签名,而推送端点仍绑定旧公钥。推送服务返回 403,在这里不是无缘无故拒绝一条好消息,而是在执行订阅建立时约定的身份限制。
RFC 8292 的约束解释了为什么不能简单“接受最新密钥算了”。受限订阅要求发送方证明自己持有与创建时公钥对应的私钥。假如发送方可以自行宣布另一把钥匙也有效,原来的约束就失去意义。因此,更换应用服务器公钥需要用户代理建立新的订阅;旧地址并不会因服务器宣布轮换而自动重新绑定。
不过,403 并非密钥轮换的专属诊断码。签名有误、受众不正确、令牌过期等问题也可能导致认证被拒绝。只看一个状态码就批量重建订阅,可能花费很多请求,却没有触及真正的问题。应先把创建时序、密钥批次与会话状态对应起来,再决定是否属于这场竞争。
还有一层容易被“密钥”二字遮住的区别。VAPID 签名用于应用服务器身份认证,推送内容加密处理的是保密性;两者的私钥材料必须分开。身份认证正确,既不代表内容已经被用户接收,也不代表用户已经阅读。把安全检查的成功记成业务结果,是另一种不必要的越界。
恢复入口不在那张集合状态表里
RFC 8620 要求先验证客户端确实能够取得发送到所给地址的数据。客户端返回正确的验证代码之后,服务器才能继续向该订阅发送后续请求。因此,“创建已受理”与“验证完成”本来就是不同状态。
这也决定了检查应放在哪里。PushSubscription/set 没有通常用于集合并发控制的 ifInState 参数,结果中也没有 oldState、newState。这里要看的 sessionState 位于外层 API 响应,指向的是 Session 对象当前状态。把普通集合更新的检查套路搬过来,可能做了很认真的一套核对,却核对了一个这里并不存在的字段。
RFC 9749 要求客户端检查返回的会话状态与预期 applicationServerKey 是否一致。在发现失配时,标准允许客户端重新尝试创建订阅,也允许销毁先前未完成的订阅。这不是要求无限重复相同请求,更不是要求绕过推送服务的身份限制。恢复的起点应当是刷新已经过时的假设。
服务器不得重试的对象也要说准:这里讨论的是这次被拒绝的推送验证,而不是宣布一切推送消息都不能重发。客户端重新建立正确绑定,与服务器在旧条件下反复发送同一验证,是两件事。失去这个区分,操作手册很容易同时写出“必须重试”和“禁止重试”,最后交给值班人员猜。
客户端界面可以保持简洁,但运维证据不能把所有中间状态挤成一个“已订阅”。至少需要能回答:创建请求是否受理,验证是否完成,最终订阅对应哪一代密钥。否则,“没有新消息”既可能是没有数据变化,也可能是通知渠道尚未真正建立。
不能把可疑的最后提醒当作兜底
原 RFC 在密钥退役安排中写了一段可选流程:向某些旧订阅发出最后一次 StateChange,促使客户端调用 PushSubscription/changes,再发现新的会话信息。问题不只是最后一条消息可能送不到;这段描述本身还有接口层面的疑点。
RFC Editor 的 RFC 9749 勘误记录 显示,Neil Jenkins 于 2026 年 7 月 31 日提交了技术勘误 9055,建议删去这一段。理由是 PushSubscription 不关联账户,不能按 RFC 8620 的 StateChange 结构放入相应通知,而且 RFC 8620 并未定义 PushSubscription/changes 方法。
截至 2026 年 9 月 7 日查阅时,这条勘误的状态仍为 Reported,即已报告,尚非 Verified。不能因此宣称标准已经完成修订,也不能推断所有产品都存在同一种故障。但 RFC 8620 的方法定义和通知结构可以独立核对。对操作方案而言,足够审慎的结论是:不要把这段有争议的调用链写成已经成立的互操作保障。
即使存在一种有效的提醒办法,也不能保证休眠客户端一定收到。RFC 8030 对推送消息规定了保留期限,推送服务可以缩短它;存活时间为零的消息不会等待一个当前不可用的设备。所谓“最后一次”,是发送端给动作起的名字,不会自动产生接收保证。
因此,真正需要验收的是客户端再次活动之后能否发现变化并恢复,而不只是服务器是否尝试提醒过。前者是一条可以测试的返回路径,后者只是一项局部动作。
IANA 的 JMAP 能力注册表 已登记这个扩展标识。登记证明的是名称协调,不是某一批设备已经通过恢复测试。采购或发布评审不能拿一个注册表条目替代对实际客户端行为的证据。
记录恢复过程,不给敏感材料续命
调查订阅问题需要线索,却不需要无限保存完整推送地址和加密材料。RFC 8620 要求销毁订阅后尽快安全擦除这些内容,而且不允许 PushSubscription/get 返回地址或密钥,即使调用方明确索取也不行。
适合长期分析的可以是非敏感的密钥批次标识、状态转换时间和处理结果,保存期限仍应受约束。“排障需要”不能成为在日志里另建一套永久订阅凭据库的理由。否则,业务系统完成了退役,观察系统却替旧材料延长了寿命。
订阅生命周期还与创建它的 API 凭据相连。凭据被撤销或失效,需要按相应规则处理,而不是统统归入网络重试。客户端也不应为了修复本机问题,删除不认识的其他 deviceClientId 的订阅。恢复的目标是重建自己的有效路径,不是把整个账户的通知关系清空再说。
这些限制没有证明某家服务已经违反规范。它们提供的是评审边界:什么可以被观察,什么可以被重建,什么不能因方便而扩大权限。
会员简报
档案背景详情
使用相应会员等级登录,即可解锁完整简报与来源注释。
仅限 Strategic Circle
Strategic Circle
所有读者均可浏览。加入并登录后可解锁档案简报。
加入 Strategic Circle仅限 Leadership Alliance
Leadership Alliance
符合条件的 IP 资产所有者和管理层可登录查看 Leadership Alliance 简报。
加入 Leadership Alliance
