摘要

  • RFC 9670 规定共享数据类型必须提供 isSubscribed、myRights 与 shareWith,但具体权限名称和语义由每一种数据类型自行定义。
  • state token 能保护并发写入,不能替代身份、有效权限、客户端可见性、通知送达、真实操作或撤销范围的证明。

所有控制面迹象都显示成功。对象的 shareWith 增加了目标 Principal,/set 把它列入 updated,newState 与旧值不同。接收者随后读取对象,也看见一个权限位为 true。然而当他执行团队以为已经放开的管理操作时,服务器返回 forbidden。

问题不在于哪一方“说谎”,而在于组织把不同对象类型中的权限键,当成了一个通用的“已授权”。

RFC 9670 的贡献是提供共用框架。Principal 可以代表个人、群组、地点、会议室或设备;ShareNotification 描述权限变化;可共享对象用统一形状表达订阅、当前权限与共享对象表。这样,日历、邮件和未来数据类型可以复用一套协作语言。

但 RFC 明确不定义“什么可以共享”,也不定义权限粒度。每个数据类型必须说明 myRights 中每个布尔键的含义。因此,一个系统中的 mayRead、mayWrite、mayAdmin 或其他键,不能靠字段形状自动获得跨产品的同义性。

shareWith 是分配表,不是执行结果

shareWith 为空表示没有与他人共享;否则它把 Principal ID 映射到一组权限。拥有合适权限的用户可以修改它。Account 的所有者不出现在表中,因为所有者权限是隐含的。

这意味着表面审计有两个陷阱。第一,表中出现某个 Principal,只证明服务器存储了一份分配。第二,表中没有所有者,并不证明所有者没有权力。

接收者看到的 myRights 是另一份事实。它描述当前用户在该对象上的数据类型特定权限。它可能受服务器政策、群组解析、对象状态或数据类型规则影响。稳健的验证顺序是:记录拥有者侧 shareWith,以接收者身份读回 myRights,再执行一项精确操作。读、改、删、管理不能被一个笼统的“access=true”替代。

state 解决竞争,不解释意图

共享表常以整张 map 更新。两位管理员从同一个旧版本出发,各自添加一个人,如果没有并发保护,后写入者可能无意间删除先写入者的授权。

RFC 8620 的 ifInState 允许客户端声明自己所依据的 state。数据类型已经变化时,服务器用 stateMismatch 中止。/set 响应还把成功的 updated 与失败的 notUpdated 分开,并返回 oldState/newState。

这些值应作为变更凭据保存:对象 ID、旧 state、提交的 map hash、ifInState、逐对象结果和新 state。它们能证明一次条件写入是否成立,却不能说明人为什么授权、选择的 Principal 是否正确、接收者是否看见通知,或后续操作是否成功。

JMAP 的 state 是同步控制,不是通用审计日志。把它提升为“权限已经在所有地方生效”,会让控制面顺序借用执行面的权威。

权限与订阅本来就不同

RFC 9670 专门区分“可以访问”与“愿意订阅”。员工可能有权浏览全公司的共享档案,却只订阅自己关心的几项。isSubscribed=false 时,资源可以不出现在日常界面。服务器甚至可以在保留访问权的同时拒绝某些订阅。

因此,“列表里没出现”不能直接判定为权限失败。Principal 查询可以显示用户有权访问哪些 Account;直接 /get 和操作测试回答授权问题;isSubscribed 与客户端渲染回答可见性问题。

这种分层也影响 StateChange。服务器通常只应为已订阅数据推送变化,不应为完全未订阅、又不属于用户的 Account 发送事件。没有推送,不等于没有权限或没有变化。

ShareNotification 是记录,不是注意力

当权限变化时,服务器应该创建 ShareNotification。它可包含对象类型、Account、对象 ID、旧/新 myRights、时间与变更者。变更者的 principalId 可以为空。

但这里没有“必达”承诺。对于群组 Principal 引发的大量变化,服务器可以不逐项通知。它还可以合并通知、限制数量、按时间清理;达到上限时,新通知可能淘汰最旧记录。RFC 同时提醒:静默淘汰本身会掩盖安全事件。

所以,notification ID 证明服务器按本地政策建立过一条记录,不证明客户端收取、界面展示或人类理解。运营记录应区分 created、coalesced、suppressed、expired、delivered、displayed 与 acknowledged。

撤销只能关闭它控制的未来

从 shareWith 删除 Principal、读回降低后的 myRights,并验证新的服务请求被拒绝,可以证明在线授权已在某个 state 和时间点关闭。

它不能让此前合法导出的文件消失,也不能撤回服务控制边界之外的复制品。RFC 9670 没有定义离线副本清除。组织应该把“新请求已拒绝”和“既有数据已回收”写成两个完全不同的承诺。

RFC 的安全章节说明了为什么这种准确性重要。可编辑的 Principal 名称可能被仿冒;短暂接触未锁定客户端的人,可以添加攻击者控制的共享对象,把瞬时入侵变成持久权限;反复改变共享状态能制造通知拒绝服务;开放的 Principal 集合会增加误分享与垃圾内容。

共同规范给出最小协调面。真正可信的链条仍需从 Principal 身份、对象所有权、条件写入、双侧读回、订阅与通知,一直延伸到实际操作和副本边界。

信息来源