Appendix B. 先例 (Prior Art)
附录 B. 先例 (Appendix B. Prior Art)
(本节为非规范性内容.)
本文中的建议是对大量应用协议规范中的建议的抽象. 为了便于比较, 并勾勒 IETF 内部关于应用服务身份验证思路的历史沿革, 本资料性章节汇集了先例: 原样收录来自多个 RFC 的文本 (唯一的改动是更改了若干引用的名称以与本文正文保持连贯, 以及按 "[...]" 标记省略无关文本).
B.1. IMAP, POP3 与 ACAP (1999)
1999 年, [USINGTLS] 就 IMAP, POP3 与 ACAP 中的应用服务身份验证规定了如下文本:
2.4. 服务器身份检查
在 TLS 协商期间, 客户端必须把自己对服务器主机名的理解, 与服务器 Certificate 消息中呈现的服务器身份进行比较, 以防止中间人攻击. 匹配按以下规则执行:
客户端必须使用它打开连接时所用的服务器主机名, 作为与服务器证书中表示的服务器名进行比较的值. 客户端禁止使用从不安全远程来源 (例如不安全的 DNS 查询) 派生的任何形式的服务器主机名. 不做 CNAME 规范化.
如果证书中存在 dNSName 类型的 subjectAltName 扩展, 它应当被用作服务器身份的来源.
匹配不区分大小写.
"*" 通配符可以用 (MAY) 作证书中最左边的名称组件. 例如, *.example.com 匹配 a.example.com, foo.example.com 等, 但不匹配 example.com.
如果证书包含多个名称 (例如多于一个 dNSName 字段), 则与其中任何一个字段匹配即视为可接受.
如果匹配失败, 客户端应当请求用户显式确认, 或者终止连接并指出服务器身份可疑.
B.2. HTTP (2000)
2000 年, [HTTP-TLS] 就 HTTP 中的应用服务身份验证规定了如下文本:
3.1. 服务器身份
一般而言, HTTP/TLS 请求通过解引用 URI 产生. 因此, 客户端已知服务器的主机名. 如果主机名可得, 客户端必须把它与服务器 Certificate 消息中呈现的服务器身份进行比较, 以防止中间人攻击.
如果客户端拥有关于服务器期望身份的外部信息, 可以省略 (MAY) 主机名检查. (例如, 客户端可能连接到地址与主机名都是动态的机器, 但客户端知道服务器将出示的证书.) 在这种情况下, 重要的是把可接受证书的范围收窄到尽可能小, 以防止中间人攻击. 在特殊情况下, 客户端干脆忽略服务器身份也可能是恰当的, 但必须明白: 这会让连接对主动攻击敞开大门.
如果存在 dNSName 类型的 subjectAltName 扩展, 必须把它用作身份. 否则, 必须使用证书 Subject 字段中的 (最具体的) Common Name 字段. 尽管使用 Common Name 是现有实践, 但它已被弃用, 鼓励认证机构改用 dNSName.
匹配按 [PKIX-OLD] 规定的匹配规则执行. 如果证书中存在多个给定类型的身份 (例如多于一个 dNSName), 与该集合中任何一个匹配即视为可接受. 名称可以包含通配符 *, 它被视为匹配任意单个域名组件或组件片段. 例如, .a.com 匹配 foo.a.com 但不匹配 bar.foo.a.com; f.com 匹配 foo.com 但不匹配 bar.com.
在某些情况下, URI 被指定为 IP 地址而非主机名. 此时, 证书中必须存在 iPAddress 类型的 subjectAltName, 并且必须与 URI 中的 IP 完全一致.
如果主机名与证书中的身份不匹配, 面向用户的客户端必须通知用户 (客户端可以让用户在任何情况下都有机会继续连接), 或以坏证书错误终止连接. 自动化客户端必须把错误记录到适当的审计日志 (如果可用), 并应当以坏证书错误终止连接. 自动化客户端可以提供停用该检查的配置项, 但必须提供启用它的配置项.
注意, 在许多情况下 URI 本身来自不受信任的来源. 上述检查对这种来源被攻破的攻击不提供保护. 例如, 如果 URI 是通过点击一个 HTML 页面获得的, 而该页面本身并非经由 HTTP/TLS 获得, 中间人就可能已替换了 URI. 为防止这种形式的攻击, 用户应当仔细检查服务器出示的证书, 判断它是否符合自己的预期.
B.3. LDAP (2000/2006)
2000 年, [LDAP-TLS] 就 LDAP 中的应用服务身份验证规定了如下文本:
3.6. 服务器身份检查
客户端必须把自己对服务器主机名的理解, 与服务器 Certificate 消息中呈现的服务器身份进行比较, 以防止中间人攻击.
匹配按以下规则执行:
客户端必须使用它打开 LDAP 连接时所用的服务器主机名, 作为与服务器证书中表示的服务器名进行比较的值. 客户端禁止使用服务器的规范 DNS 名或任何其他派生形式的名称.
如果证书中存在 dNSName 类型的 subjectAltName 扩展, 它应当被用作服务器身份的来源.
匹配不区分大小写.
允许 "*" 通配符. 如果存在, 它只适用于最左边的名称组件.
例如, *.bar.com 匹配 a.bar.com, b.bar.com 等, 但不匹配 bar.com. 如果证书中存在多个给定类型的身份 (例如多于一个 dNSName), 与该集合中任何一个匹配即视为可接受.
如果按上述检查主机名与证书中基于 dNSName 的身份不匹配, 面向用户的客户端应当通知用户 (客户端可以让用户在任何情况下都有机会继续连接), 或终止连接并指出服务器身份可疑. 自动化客户端应当关闭连接, 返回和/或记录一条指出服务器身份可疑的错误.
除本节所述的服务器身份检查之外, 客户端应当准备做进一步的检查, 以确保服务器有权提供它被观察到正在提供的服务. 客户端可能需要利用本地策略信息.
2006 年, [LDAP-AUTH] 就 LDAP 中的应用服务身份验证规定了如下文本:
3.1.3. 服务器身份检查
为防止中间人攻击, 客户端必须验证服务器的身份 (如在服务器 Certificate 消息中所呈现). 在本节中, 客户端对服务器身份的理解 (通常是用于建立传输连接的身份) 称为 "参考身份" (reference identity).
客户端确定参考身份的类型 (例如 DNS 名或 IP 地址), 并在参考身份与该类型的每个 subjectAltName 值之间进行比较, 直到产生一个匹配. 一旦产生匹配, 服务器的身份即得到验证, 服务器身份检查完成. 不同类型的 subjectAltName 以不同方式匹配. 第 3.1.3.1 至 3.1.3.3 节解释如何比较各种 subjectAltName 类型的值.
客户端可以在比较前把参考身份映射为另一种类型. 可以对参考身份能映射到的所有可用 subjectAltName 类型执行映射; 但是, 参考身份只应映射到这样一些类型: 映射本身是固有安全的 (例如从 URI 中提取 DNS 名, 与类型为 dNSName 的 subjectAltName 比较), 或者映射以安全方式执行 (例如使用 [DNSSEC], 或使用用户或管理员配置的主机到地址/地址到主机查找表).
服务器的身份也可以通过把参考身份与服务器证书 subject 字段中最后一个相对可辨识名 (RDN) 的 Common Name (CN) [LDAP-SCHEMA] 值进行比较来验证 (其中 "最后" 指 DER 编码顺序, 而非 DER 编码数据的字符串表示中的呈现顺序). 该比较使用下文第 3.1.3.1 节的 DNS 名比较规则, 但不允许通配符匹配. 尽管 Common Name 值的使用是现有实践, 但它已被弃用, 鼓励认证机构改为提供 subjectAltName 值. 注意, TLS 实现可能按 X.500 或其他约定表示证书中的 DN. 例如, 一些 X.500 实现按从左到右 (最高有效到最低有效) 的约定排列 DN 中的 RDN, 而不是 LDAP 的从右到左约定.
如果服务器身份检查失败, 面向用户的客户端应当通知用户 (这种情况下客户端可以让用户有机会继续 LDAP 会话), 或关闭传输连接并指出服务器身份可疑. 自动化客户端应当关闭传输连接, 然后返回或记录一条指出服务器身份可疑的错误, 或两者兼施.
除本节描述的服务器身份检查之外, 客户端应当准备做进一步检查, 以确保服务器有权提供它被请求提供的服务. 客户端在做出这一判定时可能需要利用本地策略信息.
3.1.3.1. DNS 名的比较
如果参考身份是一个国际化域名, 符合规范的实现必须先把它转换为 ASCII 兼容编码 (ACE) 格式 (按 RFC 3490 [IDNA2003] 第 4 节的规定), 再与类型为 dNSName 的 subjectAltName 值比较. 具体而言, 符合规范的实现必须按如下方式执行 RFC 3490 第 4 节规定的转换操作:
在步骤 1 中, 域名应被视为 "stored string";
在步骤 3 中, 设置名为 "UseSTD3ASCIIRules" 的标志;
在步骤 4 中, 对每个标签执行 "ToASCII" 操作; 并且
在步骤 5 中, 把所有标签分隔符改为 U+002E (句点).
执行 "to-ASCII" 转换之后, 必须按 RFC 3490 第 3 节规定的规则比较 DNS 标签与名称是否相等.
'*' (ASCII 42) 通配符允许出现在类型为 dNSName 的 subjectAltName 值中, 且只能作为该值中最左 (最低有效) 的 DNS 标签. 该通配符匹配服务器名中最左的任意 DNS 标签. 也就是说, subject *.example.com 匹配服务器名 a.example.com 与 b.example.com, 但不匹配 example.com 或 a.b.example.com.
3.1.3.2. IP 地址的比较
当参考身份是 IP 地址时, 必须把该身份转换为 "网络字节序" 的八位组串表示 [IP] [IPv6]. 对 RFC 791 规定的 IP 版本 4, 该八位组串恰好含四个八位组; 对 RFC 2460 规定的 IP 版本 6, 恰好含十六个八位组. 然后将该八位组串与类型为 iPAddress 的 subjectAltName 值比较. 若参考身份八位组串与值八位组串完全相同, 则发生匹配.
3.1.3.3. 其他 subjectName 类型的比较
客户端实现可以按其他文档的描述, 支持对其他类型 subjectAltName 值的匹配.
B.4. SMTP (2002/2007)
2002 年, [SMTP-TLS] 就 SMTP 中的应用服务身份验证规定了如下文本:
4.1 STARTTLS 命令之后的处理
[...]
是否相信 TLS 协商中另一方的真实性是本地事务. 不过, 这类决策的一些一般规则是:
- SMTP 客户端多半只想认证这样的 SMTP 服务器: 其服务器证书中的域名正是客户端认为自己正连接到的域名.
[...]
2006 年, [SMTP-AUTH] 就 SMTP 中的应用服务身份验证规定了如下文本:
- 在 TLS 上使用 SASL PLAIN 的附加要求
[...]
在成功的 [TLS] 协商之后, 客户端必须把自己对服务器主机名的理解, 与服务器 Certificate 消息中呈现的服务器身份进行比较, 以防止中间人攻击. 如果匹配失败, 客户端禁止尝试使用 SASL PLAIN 机制进行认证. 匹配按以下规则执行:
客户端必须使用它打开连接时所用的服务器主机名, 作为与服务器证书中表示的服务器名进行比较的值. 客户端禁止使用从不安全远程来源 (例如不安全的 DNS 查询) 派生的任何形式的服务器主机名. 不做 CNAME 规范化.
如果证书中存在 dNSName 类型的 subjectAltName 扩展, 它应当被用作服务器身份的来源.
匹配不区分大小写.
"*" 通配符可以用 (MAY) 作证书中最左边的名称组件. 例如, *.example.com 匹配 a.example.com, foo.example.com 等, 但不匹配 example.com.
如果证书包含多个名称 (例如多于一个 dNSName 字段), 则与其中任何一个字段匹配即视为可接受.
B.5. XMPP (2004)
2004 年, [XMPP-OLD] 就 XMPP 中的应用服务身份验证规定了如下文本:
14.2. 证书验证
当一个 XMPP 对等端与另一个对等端安全通信时, 它必须验证对端的证书. 有三种可能的情形:
情形 #1: 对端含有一个终端实体 (End Entity) 证书, 它看起来经由一条终止于信任锚的认证路径获得认证 (如 [PKIX] 第 6.1 节所述).
情形 #2: 对端证书由验证方所不知道的证书权威认证.
情形 #3: 对端证书是自签名的.
在情形 #1 中, 验证方必须做以下两件事之一:
按 [PKIX] 的规则验证对端证书. 随后应当按 [HTTP-TLS] 所述规则对照对端的期望身份检查该证书, 但如果存在 "xmpp" 类型的 subjectAltName 扩展, 必须把它用作身份. 如果这些检查之一失败, 面向用户的客户端必须通知用户 (客户端可以让用户在任何情况下都有机会继续连接), 或以坏证书错误终止连接. 自动化客户端应当终止连接 (以坏证书错误) 并把错误记录到适当的审计日志. 自动化客户端可以提供停用该检查的配置项, 但必须提供启用它的配置项.
对端应当把证书连同整条认证路径一并出示给用户以供批准. 对端必须缓存该证书 (或某种不可伪造的表示, 例如哈希). 在将来的连接中, 对端必须验证出示的是同一证书, 并在证书已变化时通知用户.
在情形 #2 与情形 #3 中, 实现应当按上文 (2) 行事.
尽管 [XMPP-OLD] 定义了自己的规则, [XMPP] 就 XMPP 中的应用服务身份验证复用了本文的规则.
B.6. NNTP (2006)
2006 年, [NNTP-TLS] 就 NNTP 中的应用服务身份验证规定了如下文本:
- 安全考虑
[...]
在 TLS 协商期间, 客户端必须把自己对服务器主机名的理解, 与服务器 Certificate 消息中呈现的服务器身份进行比较, 以防止中间人攻击. 匹配按以下规则执行:
客户端必须使用它打开连接时所用的服务器主机名 (或 TLS "server_name" 扩展 [TLS] 中指定的主机名), 作为与服务器证书中表示的服务器名进行比较的值. 客户端禁止使用从不安全远程来源 (例如不安全的 DNS 查询) 派生的任何形式的服务器主机名. 不做 CNAME 规范化.
如果证书中存在 dNSName 类型的 subjectAltName 扩展, 它应当被用作服务器身份的来源.
匹配不区分大小写.
"*" 通配符可以用 (MAY) 作证书中最左边的名称组件. 例如, *.example.com 匹配 a.example.com, foo.example.com 等, 但不匹配 example.com.
如果证书包含多个名称 (例如多于一个 dNSName 字段), 则与其中任何一个字段匹配即视为可接受.
如果匹配失败, 客户端应当请求用户显式确认, 或以 QUIT 命令终止连接并指出服务器身份可疑.
此外, 客户端必须验证其连接的服务器的身份与这些服务器出示的公钥之间的绑定. 客户端应当实现 [PKIX] 第 6 节的算法做一般证书验证, 但可以用达到同等验证水平的其他验证方法补充该算法 (例如把服务器证书与本地已验证证书与身份绑定的存储进行比较).
B.7. NETCONF (2006/2009)
2006 年, [NETCONF-SSH] 就 NETCONF 中的应用服务身份验证规定了如下文本:
- 安全考虑
在把基于口令的认证数据或任何配置或状态数据发送给服务器或从服务器接收之前, 客户端必须按本地策略验证并认证服务器的身份. 在向客户端发送或从客户端接收任何配置或状态数据之前, 服务器也必须按本地策略验证并认证客户端的身份, 以确保入站客户端请求是合法的. 任何一方都不应当与身份未知, 意外或不正确的对端建立 NETCONF over SSH 连接.
2009 年, [NETCONF-TLS] 就 NETCONF 中的应用服务身份验证规定了如下文本:
3.1. 服务器身份
在 TLS 协商期间, 客户端必须仔细检查服务器出示的证书, 判断它是否符合客户端的期望. 特别是, 客户端必须把自己对服务器主机名的理解, 与服务器 Certificate 消息中呈现的服务器身份进行比较, 以防止中间人攻击.
匹配按以下规则执行 (仿照 [NNTP-TLS] 的示例):
客户端必须使用它打开连接时所用的服务器主机名 (或 TLS "server_name" 扩展 [TLS] 中指定的主机名), 作为与服务器证书中表示的服务器名进行比较的值. 客户端禁止使用从不安全远程来源 (例如不安全的 DNS 查询) 派生的任何形式的服务器主机名. 不做 CNAME 规范化.
如果证书中存在 dNSName 类型的 subjectAltName 扩展, 必须把它用作服务器身份的来源.
匹配不区分大小写.
"*" 通配符可以用 (MAY) 作证书中最左边的名称组件. 例如, *.example.com 匹配 a.example.com, foo.example.com 等, 但不匹配 example.com.
如果证书包含多个名称 (例如多于一个 dNSName 字段), 则与其中任何一个字段匹配即视为可接受.
如果匹配失败, 客户端必须请求用户显式确认, 或终止连接并指出服务器身份可疑.
此外, 客户端必须验证其连接的服务器的身份与这些服务器出示的公钥之间的绑定. 客户端应当实现 [PKIX] 第 6 节的算法做一般证书验证, 但可以用达到同等验证水平的其他验证方法补充该算法 (例如把服务器证书与本地已验证证书与身份绑定的存储进行比较).
如果客户端拥有关于服务器期望身份的外部信息, 可以省略 (MAY) 主机名检查.
B.8. Syslog (2009)
2009 年, [SYSLOG-TLS] 就 Syslog 中的应用服务身份验证规定了如下文本:
5.2. 主体名称授权
实现必须支持 (MUST) 认证路径验证 [PKIX]. 此外, 它们必须支持 (MUST) 使用本地配置的主机名指定被授权的对等端, 并按以下方式把该名称与证书匹配.
实现必须支持 (MUST) 把本地配置的主机名与 subjectAltName 扩展字段中的 dNSName 匹配, 并应当 (SHOULD) 支持把该名称与主体可辨识名称的 common name 部分检查比对.
subjectAltName 扩展的 dNSName 中允许出现 '*' (ASCII 42) 通配符 (如果用 common name 存储主机名, 则在 common name 中亦然), 但只能作为该值中最左 (最低有效) 的 DNS 标签. 该通配符匹配服务器名中最左的任意 DNS 标签. 也就是说, subject *.example.com 匹配服务器名 a.example.com 与 b.example.com, 但不匹配 example.com 或 a.b.example.com. 实现必须支持 (MUST) 如上规定的证书通配符, 但可以提供 (MAY) 停用它们的配置选项.
本地配置的名称可以 (MAY) 含有用于匹配一段取值范围的通配符. 所支持的通配符类型可以 (MAY) 比 subject 名称中允许的更灵活, 从而可以支持面向不同环境的各种策略. 例如, 某项策略可以允许基于信任根的授权: 由特定 CA 信任根签发的所有凭证都被授权.
如果本地配置的名称是国际化域名, 符合规范的实现必须把它转换为 ASCII 兼容编码 (ACE) 格式再做比较, 按 [PKIX] 第 7 节的规定.
实现可以 (MAY) 支持把本地配置的 IP 地址与 subjectAltName 扩展中存储的 iPAddress 匹配. 此时, 本地配置的 IP 地址按 [PKIX] 第 4.2.1.6 节的规定转换为八位组串. 若该八位组串等于 subjectAltName 扩展中 iPAddress 的值, 则发生匹配.
B.9. SIP (2010)
2010 年, [SIP-CERTS] 就 SIP 中的应用服务身份验证规定了如下文本:
7.2. 比较 SIP 身份
当实现 (客户端或服务器) 把两个值作为 SIP 域身份进行比较时:
实现必须只比较每个 SIP 域标识符的 DNS 名称组件; 实现禁止在比较中使用任何 scheme 或参数.
实现必须把值作为 DNS 名比较, 这意味着比较按 [DNS-CASE] 的规定不区分大小写. 实现必须按 [PKIX] 第 7.2 节的规定处理国际化域名 (IDN).
实现必须完整地匹配这些值:
实现禁止匹配后缀. 例如, "foo.example.com" 不匹配 "example.com".
实现禁止匹配任何形式的通配符, 例如以 "." 或 "*." 开头的通配符与其他任何 DNS 标签或标签序列匹配. 例如, "*.example.com" 只匹配 "*.example.com", 而不匹配 "foo.example.com". 类似地, ".example.com" 只匹配 ".example.com", 不匹配 "foo.example.com.".
[HTTP-TLS] 允许 dNSName 组件含有通配符; 例如 "DNS:*.example.com". [PKIX] 虽未明确禁止, 但把通配符的解释留给各具体规范. [SIP] 未就证书中通配符的出现提供任何指导. 通过上述规则, 本文档禁止 SIP 域的证书中出现此类通配符.
B.10. SNMP (2010)
2010 年, [SNMP-TLS] 就 SNMP 中的应用服务身份验证规定了如下文本:
如果服务器出示的证书已通过到某个配置信任锚的认证路径验证 [PKIX], 且存在 snmpTlstmAddrServerFingerprint 值为零长度的活跃行, 那么 snmpTlstmAddrServerIdentity 列含有期望的主机名. 随后按以下方式把该期望主机名与服务器的证书比较:
实现必须支持 (MUST) 把期望主机名与 subjectAltName 扩展字段中的 dNSName 匹配, 并可以支持 (MAY) 把该名称与主体可辨识名称的 CommonName 部分检查比对.
subjectAltName 扩展的 dNSName 中允许出现 '*' (ASCII 0x2a) 通配符 (如果用 common name 存储主机名, 则在 common name 中亦然), 但只能作为该值中最左 (最低有效) 的 DNS 标签. 该通配符匹配服务器名中最左的任意 DNS 标签. 也就是说, subject *.example.com 匹配服务器名 a.example.com 与 b.example.com, 但不匹配 example.com 或 a.b.example.com. 实现必须支持 (MUST) 如上规定的证书通配符, 但可以提供 (MAY) 停用它们的配置选项.
如果本地配置的名称是国际化域名, 符合规范的实现必须把它转换为 ASCII 兼容编码 (ACE) 格式再做比较, 按 [PKIX] 第 7 节的规定.
如果期望主机名不满足这些条件, 则必须关闭 (MUST) 连接.
B.11. GIST (2010)
2010 年, [GIST] 就通用互联网信令传输 (General Internet Signalling Transport) 中的应用服务身份验证规定了如下文本:
5.7.3.1. TLS 中的身份检查
在 TLS 认证之后, 节点必须检查对端呈现的身份, 以防中间人攻击, 并验证对端有权在 GIST 层参与信令. 授权检查通过把呈现的身份依次与每个授权对等数据库 (APD, Authorised Peer Database) 条目比较来完成, 如第 4.4.2 节所述. 本节定义针对单个 APD 条目的身份比较算法.
对于使用 X.509 证书的 TLS 认证, 来自 DNS 名称空间的身份必须对照证书中存在的每个 dNSName 类型的 subjectAltName 扩展检查. 如果不存在此类扩展, 则必须把该身份与证书 Subject 字段中的 (最具体的) Common Name 比较. 把 DNS 名与 dNSName 或 Common Name 字段匹配时, 匹配不区分大小写. 此外, "*" 通配符可以用 (MAY) 作证书或 APD 中身份的最左边名称组件. 例如, APD 中的 *.example.com 会匹配 a.example.com, foo.example.com, *.example.com 等的证书, 但不匹配 example.com. 类似地, *.example.com 的证书对 a.example.com, foo.example.com, *.example.com 等的 APD 身份有效, 但对 example.com 无效.
此外, 节点必须验证它所连接对端的身份与该对端出示的公钥之间的绑定. 节点应当实现 [PKIX] 第 6 节的算法做一般证书验证, 但可以用达到同等验证水平的其他验证方法补充该算法 (例如把服务器证书与本地已验证证书与身份绑定的存储进行比较).
对于使用预共享密钥的 TLS 认证, psk_identity_hint 中的身份 (对应服务器身份, 即响应节点) 或 psk_identity 中的身份 (对应客户端身份, 即查询节点) 必须与 APD 中的身份比较.