摘要

  • RFC 5365 定义了一个寻呼模式 SIP 即时消息名单服务:客户端在一条 MESSAGE 中提交扁平 URI 名单和消息载荷,服务作为专门的 B2BUA,为每位规范化收件人新建一条 MESSAGE。
  • 加密给名单服务的 S/MIME 或其他安全正文不得原样复制给收件人。服务应复制剩余的有效正文,并在只剩一部分时移除 multipart/mixed 外壳;它还可能为具体收件人新建并加密 recipient-list-history。
  • 因而,密码学保护必须记录保护对象、发起者、受众、密钥与变换边界。相同文字、相同哈希或相同 From 都不能证明事务、身份权威、隐私决定、下游接受或实际送达也保持不变。

密文首先回答“给谁看”

加密算法常被描述为给内容加上一层强度,但加密首先建立的是关系:某一段内容由谁产生,使用什么机制,预期由谁持有密钥并解释。脱离受众谈“它是加密的”,就像脱离法院谈“它有印章”一样不完整。

RFC 5365 的输入可以是 multipart MESSAGE。一部分承载 RFC 4826 规定的扁平名单,一部分承载文本、图片等即时消息内容,还可能包含用于服务处理的安全正文。客户端通过 recipient-list-message 选项声明需要这类能力。

如果安全正文是加密给名单服务的,服务能够解密并据此处理请求。Bob 不因此成为该密文的受众,也不应收到那一部分。规范明确要求不要把面向服务自身的安全正文复制到输出请求。

这不是安全信息丢失,而是安全边界被正确执行。把密文完整转发给 Bob,既不会给他增加可验证的端到端保护,还可能泄露协议结构、诱发错误处理,或者让审计系统误以为保护关系延伸到了收件人。

服务消费了一个对象,又创建了另一个对象

名单服务不是被动的字节中继。它在输入侧作为服务器,在输出侧作为客户端,是一个专门的 B2BUA。它解析名单,处理为自己准备的正文,然后为每位收件人构造新的请求。

其他正文,例如真正的文字或图片载荷,通常应被复制。但复制发生在正文部件层,而不是整条 SIP 请求层。若删除名单与服务专用安全部分后只剩一项,服务必须移除 multipart/mixed 包装。

于是,Bob 收到的请求可能没有原来的 MIME boundary,没有相同的 Content-Disposition 组合,也没有相同的整体字节序列。它仍可携带语义相同的消息载荷。合规的变换恰恰会破坏整包哈希相等。

验证模型应记录每个输入部件的媒体类型、处置方式、哈希、预期受众和允许变换;然后记录输出部件及新增、删除原因。只对渲染后的文字做比较,会漏掉图片、附件或处置变化;要求全包字节相等,又会拒绝规范要求的重组。

新的收件人历史需要新的保护

为支持“回复全部”等体验,服务可以构造 recipient-list-history。它依据 RFC 5364 的 To、Cc、Bcc、匿名和计数规则生成,不是把原名单原封不动附给每个人。

Bob 看到的是为 Bob 构建的披露视图。Carol 可能得到另一份视图。Bcc 成员不应因一个方便功能而暴露,匿名条目也不能在重组时恢复身份。RFC 5365 建议用接收者的公钥加密这份历史。

这里出现了新的密码学动作。输入安全正文的受众是名单服务;输出历史正文的受众是具体接收者。即使二者都使用 S/MIME,“受保护”也不是同一条事实。

审计记录必须把历史视图绑定到目标:输入名单版本、复制控制规则、被包含与排除的条目、视图哈希、加密受众及结果。证明消息文字正确送达,不能替代证明收件人关系没有错误披露。

新请求拥有新的事务外壳

对每个收件人,服务应创建新的 To、Call-ID 与独立的 CSeq 计数,初始化 Max-Forwards,并加入自己的 Via。Request-URI 也从名单服务变为具体目的地。

这些字段不是装饰。Call-ID 与 CSeq 参与标识和排序,Via 让响应沿正确路径返回,Max-Forwards 给新动作设定环路预算。载荷相同,事务身份仍然是新的。

若系统用输入 Call-ID 搜索所有输出,就会丢失子事务;若只保存输出 Call-ID,又会丢失它们来自同一输入的因果联系。正确做法是另设稳定的执行 ID,把输入事务、规范收件人、意图操作与每次尝试连接起来。

这个父子关系也决定重试范围。某一收件人的结果未知,不应自动重放整组已经完成的消息。新事务的独立性必须在数据模型里保留,而不能被一个总状态压平。

可见发件人与密码学身份是两条证据

输出 From 值原则上应与输入 From 一致,但要服从隐私要求;From tag 不应像同一对话端点仍在继续那样被复制。若隐私服务与名单服务共置,隐私规则优先。

Bob 因此可能看到 Alice 的名字。这种连续性对人有用,却不能证明 Bob 端到端认证了 Alice。名单服务可能先认证 Alice,再以自身权威重建请求并选择显示哪个地址。

P-Asserted-Identity 还有独立的信任条件。断言若来自可信来源,且输出第一跳仍可信,服务必须传播;若下一跳不可信且请求了隐私,就不得发送。服务也可以在自己完成认证并能映射到 SIP 或 SIPS URI 时创建断言。

每条断言都应保留来源、认证方法、映射规则、隐私值、输入信任、输出第一跳信任以及最终包含或抑制决定。单独记录“PAI 存在”无法说明它为什么有权出现。

凭据只在相应的 realm 内回答问题

Authorization 与 Proxy-Authorization 回应的是某个认证域的挑战。若 realm 属于 MESSAGE 名单服务,服务不应把凭据复制到输出请求。Alice 证明自己有权进入中介,不代表她的秘密可以交给 Bob 的服务器。

若字段指向另一 realm,RFC 5365 要求复制相应值。规则不是一律清除,也不是一律保留,而是根据提出挑战的权威判断。

观测系统不应为了说明决定而记录原始凭据。它可以保存凭据类型、不可逆标识、realm 分类、复制或抑制结果及目标信任环境。这样既能审计,也不会让日志变成新的秘密仓库。

这也解释了为什么“载荷一致”与“认证一致”无关。载荷可以完全相同,进入名单服务和进入下游域所需的身份权威却不同。

URI 中的指示不能改变服务本身

SIP URI 可以通过问号组件携带某些 header 提示。服务可以逐项决定是否遵从,例如为某一目的地加入 Accept-Contact。特殊的 body hname 不应提供替代正文,服务可以丢弃它。

URI 还可以包含 method 参数。RFC 5365 的界线十分明确:MESSAGE 名单服务只生成 MESSAGE,必须忽略要求其他方法的参数。名单数据不能把一个消息服务暗中变成 INVITE 或其他动作的发起者。

这是一条权威次序。调用者可在合同允许范围内提供偏好,但服务合同决定它能做什么。日志应列出哪些 URI 组件被接受、拒绝或忽略,而不是只留下最终请求,让人误以为所有输入都被执行。

202 只为“接收并尝试”作证

服务收到输入后返回 202 Accepted。规范特意说明,这个状态不提供所生成 MESSAGE 是否成功送达的信息。它证明请求被接收,服务将尝试执行。

这种有限性是异步系统的诚实表达。202 并不弱,只是主语和时间都很明确:名单服务此刻接受了任务。它不能提前证明尚未创建的事务、尚未选择的路由和用户尚未体验的结果。

如果送达重要,就需要后续证据:输出请求已创建、下游 SIP 响应已观察、应用层回执已收到,或终端效果已被独立确认。RFC 5365 把具体的送达状态设计留在范围外,这不等于允许产品用 202 填补空白。

相邻的 RFC 5363 更广泛地处理一对多结果。本文的独立焦点是:一个看似只复制载荷的服务,实际上同时重建了事务与安全表面,后续结果依赖这些重建。

注册表规范了名称,不负责运行事实

IANA 登记 recipient-list-message 和相关正文处置名称,使实现能够协商、识别与解析。登记能证明共享标识存在,不能证明某台服务器正确处理身份、隐私、加密受众或某次投递。

RFC 5365 于 2008 年 10 月以 Standards Track 发布。RFC 3851 后来在包括 RFC 8551 的 S/MIME 演进中被取代。今天选择算法与格式应遵循现行规范,但“安全对象属于特定受众”的分析边界仍然成立。

Lu Heng 的“最小初始规范”笔记提供了明确披露的分析视角:共享层只标准化必要合同,未来决定留给掌握本地信息的参与者。选项标签与正文格式属于共享层;信任、realm、隐私和结果证明仍是本地判断。

他的“现实层”笔记补充了另一点:一个载荷哈希是内容连续性的符号证据,不是事务、权威或实际送达的替身。协议事实来自 RFC 与 IANA;这些笔记只用于解释治理含义。