摘要

  • RFC 5364 让 relay 从一份展开后的 URI 名单生成逐接收者历史。缺少 copyControl 时默认是 bcc;盲送条目从他人的副本中消失,匿名条目则可以只留下占位 URI 与数量。
  • 重复 URI 原则上只产生一次请求,可见性按 to、cc、bcc 取最高优先级;当 bcc 与 anonymize 同时存在时,bcc 优先。规范化和披露判断必须分别留下收据。
  • recipient-list-history 正文为兼容旧终端而标为可选。它不能证明地址存在、可达、接受、参与或应被计费;TLS 与 S/MIME 也只能保护传输保管,不能替历史的真实性背书。

重复项不是无意义的脏数据

资源名单可以嵌套。两个分支展开后可能得到按照 URI 方案比较规则等价的地址,而原始字符串并不完全相同。反过来,长得相似的字符串也可能仍指向不同目的地。

RFC 5364 认为,对同一接收者发送多次请求没有合理用途。系统应只发一次,并在冲突的复制控制值中选择 to,其次 cc,最后 bcc。

这条顺序直接影响披露。若数据库“保留第一条”,输入顺序改变就可能把公开接收者变成盲送;若简单保留最后一条,结果同样不稳定;若发两次,终端可能收到两份互相矛盾的历史。

审计记录必须保存原始 URI、比较算法及版本、碰撞组、每个来源路径、所有控制属性、胜出的可见性和唯一输出请求。只有最终去重后的地址数组,无法解释为什么该地址出现在别人视图里。

RFC 5363 已讨论一般性的名单展开、放大与逐项结果。本篇只处理更窄的控制面:当同一身份携带不同披露意图时,哪一种意图进入逐接收者投影。

缺字段时,系统没有自由发挥

条目未写 copyControl,规范就把它视为 bcc。旧列表、迁移遗漏或只支持基础 schema 的生产者,不会因此获得公开地址的默认权。

显式 bcc 与默认得到的 bcc 在输出上相同,在诊断上不同。前者是作者表达;后者说明 relay 对不完整输入应用了保守规则。

因此要保留 XML 原始字节与哈希、schema 版本、属性是否存在、解析器版本、默认值决策和最终类别。若规范化阶段直接补上字段并抹掉“原来缺失”,后续无法区分真实意图与安全兜底。

升级解析库时,应让相同的缺字段 fixture 继续生成盲送处理。一个默认值回归就可能把多年旧名单从私密变为可见。

relay 生成的是观察者视图

资源名单是执行输入,不是每个人都会收到的共同文本。relay 展开名单、解决冲突,然后为每个输出请求构造 recipient-list-history。

to、cc 可以保持可见;bcc 对其他人不可见。盲送接收者自己的那份副本可以保留它本人的 URI,用来提醒终端:如果回复所有人,就可能暴露自己。

所以,同一次 fan-out 产生不同正文哈希可能完全正确。判断差异是否正确,必须知道观察者是谁、采用哪一版规则、哪些条目被显示、隐藏或替换。

建立从原始名单哈希到展开结果,再到逐接收者请求 ID 和历史正文哈希的映射。若系统只保留一份“最终名单”,既证明不了隐藏正确,也证明不了披露正确。

名单作者拥有提交操作的权限,relay 承担执行披露规则的责任,终端只接收其被允许看见的视图。这三层不能合并成一个“参与者名单”。

bcc 与匿名化泄露的维度不同

bcc 从其他接收者的历史中移除条目。anonymize=true 则可以保留规范定义的匿名 SIP 占位符,并用 count 表示这个占位符代表几个隐藏条目。

匿名化隐藏身份,却披露存在和数量。“有四名匿名接收者”在谈判、事件响应或敏感会议中仍然是实质信息。只扫描真实 URI 是否出现,会漏掉基数泄露。

若同一条目同时标记 bcc 和 anonymize,bcc 优先。此时输出匿名占位符就是错误,因为它泄露了盲送规则本应隐藏的存在。

每个投影要记录源属性、优先级规则、完全省略的集合、匿名集合、count 值以及渲染正文。产品界面不能把这些状态都压成一个含糊的“隐藏”。

隐私测试也要拆成两项:身份有没有泄露,群体规模有没有泄露。

回复所有人是终端侧的第二道边界

relay 正确应用 bcc 后,终端仍可能通过“回复所有人”泄露盲送接收者。协议设计因此要求:当自己的 URI 不在历史中,或被标记为盲送时,用户代理应阻止或限制这项动作。

识别“自己”并不简单。一个人可能有别名、转发地址和多个账户。误判会造成两种相反结果:不必要地禁用正常回复,或把盲送身份暴露出去。

历史也可能被伪造,因此终端不能在没有验证上下文时把它当绝对真相。应记录收到的正文、解析结果、本地选择的身份、匹配过程、按钮状态与最终发出的收件人集合。

服务端的正确投影不是终端保密成功的收据。最终检查必须落到真正发送的回复上。

可选正文允许“请求成功、历史未处理”

历史使用 recipient-list-history disposition,并应带 handling=optional。旧终端不理解 multipart 或新 disposition 时,仍可接受主 SIP 请求而忽略历史部分。

于是系统有两种独立状态:请求被接收,历史被消费。前者不推出后者。“带历史送达”可能只意味着 relay 附加了字节,并不证明终端保存、解析、显示或用它控制回复。

保存 MIME 边界、disposition、handling 参数、终端能力、解析结果、显示结果与降级路径。静默丢弃可选部分也应成为可观察事件。

兼容性维持了基础服务,却可能移除防止盲送泄露的上下文。对敏感业务,是否允许这种降级必须由明确政策决定。

历史不是到场名单

规范明确警告,recipient history 不能证明真实参与者。一个 URI 可能不存在、不可达、未接听或拒绝;终端可能是自动程序;人也可能用另一身份加入。

它同样不能成为计费依据。被邀请不是消费服务,生成请求不是接受会话,出现在视图中不提供时长、资源用量或付款责任。

历史还可以被伪造。XML 语法有效,只说明结构符合规则;签名和加密可以保护某一方发出的字节,却不能把虚假陈述变成事实。

后续证据必须独立保存:输出请求、端点响应、经认证的加入事件、媒体参与、持续时间、资源使用和账单事件。它们可以相关联,不能被名单成员身份取代。

本篇的核心边界就是:历史回答“这次请求附带了怎样的披露视图”,不回答“后来谁真的在那里”。

加密保护保管,不保护语义正确

接收者关系本身敏感,所以认证、授权、TLS 与 S/MIME 都重要。它们分别在信任模型内保护链路或内容。

但它们不证明 relay 读取了正确版本、URI 比较无误、重复优先级正确、bcc 胜过匿名化或 count 与隐藏项一致。它们也不证明终端正确呈现,更不证明会话结果。

分别记录传输 peer、证书或密钥、验证结果与保护范围;再记录输入哈希、变换引擎版本、规则版本和逐接收者输出哈希。

安全通道可以无损传递一个错误投影。不能把“TLS 成功”改写成“名单真实完整”。

投影账本要保存被丢弃的信息

第一张收据冻结提交 principal、授权策略、原始 XML 与请求上下文。第二张记录嵌套展开图。第三张记录 URI 比较、规范化和碰撞组。

第四张保留显式值、默认 bcc、匿名标记、重复项优先级与 bcc 对匿名化的优先级。第五张按接收者列出可见、完全隐藏和匿名替换的条目,并把正文哈希绑定到输出请求。

之后的收据属于终端和真实世界:可选正文是否被识别、是否显示、是否禁用回复所有人、请求响应、实际参与与计费事件。

系统不仅要保存“看见了什么”,还要保存“为什么没看见”。只留输出无法证明隐藏对象正确;只留主名单无法证明具体披露结果。

测试要逐观察者比对字节

fixture 至少覆盖:缺少 copyControl;显式 to、cc、bcc;一个和多个匿名项;bcc 与匿名化并存;等价 URI 带冲突属性;盲送接收者自己的副本;普通可见接收者副本;忽略可选部分的旧终端。

对每例同时断言请求数量和历史正文精确字节。再测试自己的 URI 识别、界面显示和回复控制。最后验证出席与计费逻辑从未把历史成员身份当作真实事件。

攻击测试可以在授权后替换名单、调换重复项顺序、移除属性、修改匿名 count、伪造历史、剥离可选正文和重放旧投影。接受任何变体都应留下明确规则收据。

RFC 5364 于 2008 年 10 月以 Proposed Standard 发布;本次捕获的 RFC Editor errata 页面没有显示匹配项。这只是文档状态,不表示某个当前产品已经部署,也不支持现实事件或采用率结论。