非官方中文译本声明:本页为 IETF RFC 5802《Salted Challenge Response Authentication Mechanism (SCRAM) SASL and GSS-API Mechanisms》 的中文译本,由 ztpop.net 整理翻译,仅供学习参考。RFC 文档由 IETF 发布,受 BCP 78 与 IETF 信托法律条款约束;本译本保留原文编号与结构,权威性以英文原文为准。英文原文见 rfc-editor.org/rfc/rfc5802。
RFC 5802:SCRAM SASL 机制
摘要
互联网应用协议最广泛部署和使用的安认证机制,是通过由传输层安全(TLS)保护的信道来传输明文口令。该机制存在一些显著的安全隐患,而借助受 TLS 保护的质询响应认证机制本可解决这些隐患。遗憾的是,目前处于标准轨道上的质询响应机制均未能满足大规模部署所需的各项要求,仅在有限的范围内取得了成功。
本规范描述了一系列简单认证与安全层(SASL;RFC 4422)认证机制,称为加盐质询响应认证机制(Salted Challenge Response Authentication Mechanism,SCRAM),它既能消除上述安全隐患,又能满足可部署性要求。当与 TLS 或等效的安全层结合使用时,该系列中的某个机制可以改善应用协议认证的现状,并为未来的应用协议标准提供一个合适的"强制实现(mandatory-to-implement)"机制选项。
本备忘录的状态
这是一份互联网标准跟踪(Standards Track)文档。
本文档是互联网工程任务组(IETF)的成果,代表了 IETF 社区的共识,已通过公众评审,并经互联网工程指导组(IESG)批准发布。有关互联网标准的更多信息,见 RFC 5741 第 2 节。
关于本文档当前状态、任何勘误以及如何提供反馈的信息,可在 http://www.rfc-editor.org/info/rfc5802 获取。
版权声明
Copyright (c) 2010 IETF 信托及被列为文档作者的个人。保留所有权利。
本文档受 BCP 78 以及 IETF 信托的《IETF 文档相关法律规定》(http://trustee.ietf.org/license-info)约束,以本文档发布之日生效的版本为准。请仔细审阅这些文档,因为它们描述了您就本文档所享有的权利与限制。从本文档中提取的代码组件必须包含《简化 BSD 许可证》文本(见信托法律条款第 4.e 节),并如《简化 BSD 许可证》所述"不提供任何担保"。
目录
- 1. 引言
- 2. 本文档使用的约定
- 2.1. 术语
- 2.2. 记法
- 3. SCRAM 算法概述
- 4. SCRAM 机制名称
- 5. SCRAM 认证交换
- 5.1. SCRAM 属性
- 5.2. 与 SASL 机制要求的符合性
- 6. 信道绑定
- 6.1. 默认信道绑定
- 7. 形式化语法
- 8. SCRAM 作为 GSS-API 机制
- 8.1. 适用于 SCRAM 的 GSS-API 主体名称类型
- 8.2. 适用于 SCRAM 的 GSS-API 逐消息令牌
- 8.3. 适用于 SCRAM 的 GSS_Pseudo_random()
- 9. 安全考量
- 10. IANA 考量
- 11. 致谢
- 12. 参考文献
- 12.1. 规范性参考文献
- 12.2. 面向 GSS-API 实现者的规范性参考文献
- 12.3. 资料性参考文献
- 附录 A. 其他认证机制
- 附录 B. 设计动机
- 作者地址
1. 引言
本规范描述了一系列称为加盐质询响应认证机制(SCRAM)的认证机制,它满足了比以往尝试更广泛地部署质询响应机制的各项要求(见附录 A 与附录 B)。当与传输层安全(TLS;见 [RFC5246])或等效的安全层结合使用时,该系列中的某个机制可以改善应用协议认证的现状,并为未来的应用协议标准提供一个合适的"强制实现"机制选项。
为求简洁,该系列机制目前不包含安全层协商 [RFC4422]。它意在与外部安全层(如 TLS 或 SSH 所提供的)结合使用,并可选用对外部安全层的信道绑定 [RFC5056]。
本文档将 SCRAM 规定为一种纯简单认证与安全层(SASL)[RFC4422] 机制,但它也符合称为"GS2" [RFC5801] 的、SASL 与通用安全服务应用程序接口(GSS-API)之间新的桥接规范。这意味着本文档同时定义了一个 SASL 机制和一个 GSS-API 机制。
SCRAM 提供以下协议特性:
- 存储在认证数据库中的认证信息本身不足以假冒客户端。这些信息经过加盐处理,以防数据库被盗时发生预存储的字典攻击。
- 服务器无法获得假冒客户端去对付其他服务器的能力(经服务器授权的代理除外)。
- 该机制允许使用经服务器授权的代理,而无需该代理在后端服务器上拥有超级用户权限。
- 支持双向认证,但只有客户端被命名(即服务器没有名称)。
- 当作为 SASL 机制使用时,SCRAM 能够把授权标识(authorization identity,见 [RFC4422] 第 2 节)从客户端传送到服务器。
另有独立文档定义了标准的 LDAPv3 [RFC4510] 属性,使得 SCRAM 认证信息能够存储于 LDAP 中,见 [RFC5803]。
关于为何其他质询响应机制被认为不够充分的深入讨论,见附录 A。关于本机制设计背后动机的更多信息,见附录 B。
2. 本文档使用的约定
本文档中的关键词"MUST(必须)"、"MUST NOT(不得)"、"REQUIRED(要求)"、"SHALL(应)"、"SHALL NOT(不应)"、"SHOULD(应该)"、"SHOULD NOT(不应该)"、"RECOMMENDED(推荐)"、"MAY(可以)"和"OPTIONAL(可选)"应按 [RFC2119] 中的描述进行解释。
形式化语法由 [RFC5234] 定义,包括 [RFC5234] 附录 B 中定义的核心规则。
以"C:" 开头的示例行由客户端发送,以"S:" 开头的由服务器发送。如果单个"C:" 或"S:" 标签适用于多行,那么这些行之间的换行仅为编辑清晰起见,并不属于实际的协议交换。
2.1. 术语
本文档使用了 [RFC4949](《互联网安全术语表》)中定义的若干术语,包括:认证(authentication)、认证交换(authentication exchange)、认证信息(authentication information)、暴力破解(brute force)、质询-响应(challenge-response)、密码学哈希函数(cryptographic hash function)、字典攻击(dictionary attack)、窃听(eavesdropping)、哈希结果(hash result)、带密钥的哈希(keyed hash)、中间人(man-in-the-middle)、现时值(nonce)、单向加密函数(one-way encryption function)、口令(password)、重放攻击(replay attack)与盐(salt)。不熟悉这些术语的读者应将该术语表作为参考。
以下给出一些澄清与补充定义:
- 认证信息(Authentication information):用于验证 SCRAM 客户端所声称身份的信息。一个 SCRAM 身份的认证信息由盐、迭代数、以及针对每个所支持的密码学哈希函数的"StoredKey"和"ServerKey"(定义见算法概述)组成。
- 认证数据库(Authentication database):用于查找与特定身份关联的认证信息的数据库。对于应用协议,LDAPv3(见 [RFC4510])常被用作认证数据库;而对于 PPP 或 802.11x 等网络层协议,使用 RADIUS [RFC2865] 更为常见。
- Base64:一种在 [RFC4648] 中定义的编码机制,将八位组串(octet string)输入转换为易于向人显示的文本输出字符串。SCRAM 中对 base64 的使用仅限于不含空白字符的规范形式。
- 八位组(Octet):一个 8 位字节。
- 八位组串(Octet string):一串 8 位字节的序列。
- 盐(Salt):在与单向加密函数结合之前,同一个口令相混合的随机八位组串。该值用于保护存储在认证数据库中的口令。
2.2. 记法
算法的伪代码描述使用以下记法:
- ":=":左侧的变量表示由右侧表达式所得的八位组串。
- "+":八位组串拼接。
- "[ ]":表达式中包含在"["与"]"内的部分在某些情形下可能不出现在结果中。相关情形见对应正文的说明。
- Normalize(str):将 SASLprep profile [RFC4013] 的"stringprep"算法 [RFC3454] 作为归一化算法应用于以 UTF-8 [RFC3629] 编码的"str"。所得字符串同样为 UTF-8。应用 SASLprep 时,"str"被当作"stored strings(已存储字符串)"处理,即未分配的 Unicode 码位被禁止(见 [RFC3454] 第 7 节)。注意,实现要么必须实现 SASLprep,要么必须禁止在"str"中使用非 US-ASCII 的 Unicode 码位。
- HMAC(key, str):以"key"所表示的八位组串作为密钥、以八位组串"str"作为输入串,应用 HMAC 带密钥哈希算法(定义于 [RFC2104])。结果的大小即为所使用哈希函数的哈希结果大小;例如对 SHA-1 而言为 20 个八位组(见 [RFC3174])。
- H(str):对八位组串"str"应用密码学哈希函数,产生一个八位组串作为结果。结果的大小取决于所使用哈希函数的哈希结果大小。
- XOR:对位于该运算符左侧的八位组串与右侧的八位组串应用异或(exclusive-or)运算。在本用法中,输出与两个输入的长度相同。
- Hi(str, salt, i):
U1 := HMAC(str, salt + INT(1)) U2 := HMAC(str, U1) ... Ui-1 := HMAC(str, Ui-2) Ui := HMAC(str, Ui-1) Hi := U1 XOR U2 XOR ... XOR Ui
其中"i"为迭代数,"+"为字符串拼接运算符,INT(g) 为整数 g 的 4 八位组编码,最高有效八位组在前。
Hi() 本质上就是 PBKDF2 [RFC2898],其中 HMAC() 作为伪随机函数(PRF),且 dkLen == HMAC() 的输出长度 == H() 的输出长度。
3. SCRAM 算法概述
下面描述一次完整的、未压缩的 SASL SCRAM 认证交换。SCRAM 并不禁止以下任一做法:将客户端首条消息与应用协议定义的 SASL 认证请求("initial client response")一起发送,或将服务器最终消息作为应用协议定义的认证交换 SASL 结果中的附加数据发送。更多细节见 [RFC4422]。
注意本节省略了一些细节,例如客户端与服务器的现时值(nonce)。更多细节见第 5 节。
首先,SCRAM 客户端持有用户名与口令(*)(或 ClientKey/ServerKey,或 SaltedPassword)。它将用户名发送给服务器,服务器据此检索相应的认证信息,即盐、StoredKey、ServerKey 以及迭代数 i。(注意,服务器实现可以选择对所有账户使用相同的迭代数。)服务器将盐与迭代数发送给客户端,客户端随后计算以下各值,并向服务器发送一个 ClientProof:
(*)注意用户名与口令都必须以 UTF-8 [RFC3629] 编码。
说明性注记:鼓励实现者创建同时使用了含非 ASCII 码位的用户名与口令的测试用例。特别地,测试那些"Unicode 标准规范化形式 C(Normalization Form C)"与"Unicode 标准规范化形式 KC(Normalization Form KC)"互不相同的码点是很有用的。此类码点的例子包括 Vulgar Fraction One Half(U+00BD)与 Acute Accent(U+00B4)。
SaltedPassword := Hi(Normalize(password), salt, i)
ClientKey := HMAC(SaltedPassword, "Client Key")
StoredKey := H(ClientKey)
AuthMessage := client-first-message-bare + "," +
server-first-message + "," +
client-final-message-without-proof
ClientSignature := HMAC(StoredKey, AuthMessage)
ClientProof := ClientKey XOR ClientSignature
ServerKey := HMAC(SaltedPassword, "Server Key")
ServerSignature := HMAC(ServerKey, AuthMessage)
服务器通过计算 ClientSignature、将其与 ClientProof 进行异或运算来恢复 ClientKey,并对 ClientKey 应用哈希函数、将结果与 StoredKey 比较,从而认证客户端。如果 ClientKey 正确,就证明客户端能够访问该用户的口令。
类似地,客户端通过计算 ServerSignature 并将其与服务器发送的值进行比较来认证服务器。若两者相等,则证明服务器能够访问该用户的 ServerKey。
AuthMessage 通过拼接认证交换中的各条消息计算得到。这些消息的格式在第 7 节定义。
4. SCRAM 机制名称
SCRAM 机制名称是一个字符串"SCRAM-",后接取自 IANA"Hash Function Textual Names"注册表(见 http://www.iana.org)的底层哈希函数名的大写形式,并可选择后接后缀"-PLUS"(见下文)。注意 SASL 机制名称限制为 20 个八位组,这意味着只能使用长度不超过 9 个八位组(20 - length("SCRAM-") - length("-PLUS"))的哈希函数名。对于底层哈希函数名长于 9 个八位组的情况,只要不与 IANA"Hash Function Textual Names"注册表中的任何其他哈希函数名冲突,就可以使用一个替代的 9 八位组(或更短)名称来构造相应的 SCRAM 机制名称。为防止将来冲突,此类替代名称应在 IANA"Hash Function Textual Names"注册表中注册。
为互操作性,所有 SCRAM 客户端与服务器都必须实现 SCRAM-SHA-1 认证机制,即使用 [RFC3174] 所定义的 SHA-1 哈希函数的 SCRAM 系列认证机制。
"-PLUS"后缀仅在服务器支持对外部信道进行信道绑定时使用。如果服务器支持信道绑定,它将通告它所支持的任意机制(例如 SCRAM-SHA-1)的"裸(bare)"版本与"加(plus)"版本(即同时通告 SCRAM-SHA-1 与 SCRAM-SHA-1-PLUS)。如果服务器不支持信道绑定,则它只通告该机制的"裸"版本(例如仅 SCRAM-SHA-1)。"-PLUS"的存在是为了允许协商是否使用信道绑定。见第 6 节。
5. SCRAM 认证交换
SCRAM 是一种 SASL 机制,其客户端应答与服务器质询消息是基于文本的、包含一个或多个由逗号分隔的属性-值对的消息。每个属性有一个单字母名称。这些消息及其属性在第 5.1 节描述,并在第 7 节定义。
SCRAM 是一种客户端首发的(client-first)SASL 机制(见 [RFC4422] 第 5 节第 2a 项),并在服务器指示成功结果时一并返回附加数据。
下面是当客户端不支持信道绑定时的一次简单 SCRAM-SHA-1 认证交换示例(使用的用户名是"user",口令是"pencil"):
C: n,,n=user,r=fyko+d2lbbFgONRv9qkxdawL
S: r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,s=QSXCR+Q6sek8bf92,
i=4096
C: c=biws,r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,
p=v0X8v3Bz2T0CJGbJQyF0X+HI4Ts=
S: v=rmF9pqV8S7suAoZWja4dJRkFsKQ=
首先,客户端发送包含以下内容的"client-first-message(客户端首条消息)":
- 一个 GS2 头,由一个标志组成,该标志指示信道绑定是"支持但未使用"、"不支持"还是"已使用",以及一个可选的 SASL 授权标识;
- SCRAM 用户名和一个随机、唯一的现时值(nonce)属性。
注意,客户端的首条消息总是以"n"、"y"或"p"开头;否则该消息无效,认证必须失败。这很重要,因为它为 GS2 的扩展性(例如增加安全层支持)留出了空间。
作为响应,服务器发送"server-first-message(服务器首条消息)",其中包含用户的迭代数 i 与用户的盐,并将其自身的现时值附加到客户端指定的现时值之后。
随后客户端发送"client-final-message(客户端最终消息)"作为应答,其中包含相同的现时值以及一个使用所选哈希函数、按前述方式计算的 ClientProof。
服务器验证现时值与证明(proof),验证授权标识(若客户端在首条消息中提供)被授权以认证标识的身份行事,最后以一个"server-final-message(服务器最终消息)"作为应答,结束认证交换。
此后,客户端通过计算 ServerSignature 并将其与服务器发送的值进行比较来认证服务器。若两者不同,客户端必须认为认证交换未成功,并可能须要断开连接。
5.1. SCRAM 属性
本节描述允许使用的属性、它们的用途以及其值的格式。所有属性名均为单个 US-ASCII 字母,且区分大小写。
注意,客户端或服务器消息中属性的顺序是固定的,但扩展属性(由"extensions"这个 ABNF 产生式描述)除外,它可以按任意顺序出现在指定位置。权威参考见第 7 节。
- a:这是一个可选属性,是 GSS-API 与 SASL 之间 GS2 [RFC5801] 桥接的一部分。该属性指定一个授权标识。客户端若想以一个用户身份认证、随后以另一个用户身份行事,可在其首条消息中包含它。
服务器收到该值后,会根据所使用的 SASL 协议 profile 验证其正确性。验证失败会导致认证交换失败。
若省略此属性(通常情况如此),则授权标识被假定为派生自由(必需的)"n"属性所指定的用户名。
服务器总是认证由"n"属性指定的用户。若"a"属性指定了不同的用户,服务器在成功通过认证与授权检查后,将该身份与连接相关联。
本字段的语法与"n"字段关于"="和","引用的语法相同。
- n:该属性指定其口令被用于认证的用户的名称(即"认证标识(authentication identity)"[RFC4422])。客户端必须在其首条发给服务器的消息中包含它。若未指定"a"属性(通常如此),则该用户名同时也是认证与授权之后与连接相关联的身份。
在向服务器发送用户名之前,客户端应使用"stringprep"算法 [RFC3454] 的"SASLprep" profile [RFC4013] 准备该用户名,将其当作查询字符串处理(即允许未分配的 Unicode 码位)。若用户名的准备失败或导致空字符串,客户端应中止认证交换(*)。
(*)交互式客户端可要求重新输入用户名值。
服务器收到用户名后,必须要么使用"stringprep"算法的"SASLprep" profile [RFC4013] 将其当作查询字符串处理(即允许未分配的 Unicode 码位)进行准备,要么准备好进行 SASLprep 感知的字符串比较和/或索引查找。若用户名的准备失败或导致空字符串,服务器应中止认证交换。
无论服务器是否使用 SASLprep 准备用户名,它都必须按收到时的原样在哈希计算中使用它。
用户名中的字符","或"="分别作为"=2C"和"=3D"发送。如果服务器收到的用户名中包含未后接"2C"或"3D"的"=",则服务器必须使认证失败。
- m:该属性为将来的扩展性保留。在本版 SCRAM 中,只要它被对端解析到,其出现在客户端或服务器消息中就必须导致认证失败。
- r:该属性指定一个由随机的可打印 ASCII 字符组成的序列(不包括","),它构成作为哈希函数输入的现时值(nonce)。该字符串不应用任何引用。如前所述,客户端在其首条消息中提供一个初值,服务器在其首条应答中用自己的现时值扩充该值。重要的是,此值对每次认证都须不同(关于如何实现这一点,见 [RFC4086] 的更多细节)。客户端必须验证后续消息中使用的现时值初始部分与它最初指定的现时值相同。服务器必须验证客户端在第二条消息中发送的现时值与它在首条消息中发送的现时值相同。
- c:这个必需的属性指定经过 base64 编码的 GS2 头与信道绑定数据。它由客户端在其第二条认证消息中发送。该属性数据由以下部分组成:
- 来自客户端首条消息的 GS2 头(回想 GS2 头包含信道绑定标志与可选的 authzid)。当且仅当客户端正在使用信道绑定时,该头才会包含信道绑定类型前缀(见 [RFC5056]);
- 后接外部信道的信道绑定数据,当且仅当客户端正在使用信道绑定时。
- s:该属性指定服务器用于该用户的、经过 base64 编码的盐。它由服务器在其首条发给客户端的消息中发送。
- i:该属性指定所选哈希函数与用户的迭代数,且必须由服务器与用户的盐一并发送。
对于 SCRAM-SHA-1/SCRAM-SHA-1-PLUS 这一 SASL 机制,服务器应公布至少为 4096 的哈希迭代数。注意,客户端实现可以缓存 ClientKey 与 ServerKey(或仅缓存 SaltedPassword)以便日后对同一服务重新认证,因为服务器很可能在重新认证时公布相同的盐值。这对于 CPU 使用受限的移动客户端可能很有用。
- p:该属性指定经过 base64 编码的 ClientProof。客户端按概述中的描述计算此值,并将其发送给服务器。
- v:该属性指定经过 base64 编码的 ServerSignature。它由服务器在其最终消息中发送,并被客户端用来验证服务器能够访问该用户的认证信息。该值按概述中的解释计算。
- e:该属性指定认证交换期间发生的错误。它由服务器在其最终消息中发送,有助于诊断认证交换失败的原因。在认证失败时,整条 server-final-message 是可选的;具体而言,服务器实现可以在不发送 server-final-message 的情况下以失败结束 SASL 交换,这会产生一个应用层错误响应而无额外往返。如果认证失败时发送了 server-final-message,则必须包含"e"属性。
- 尚待规定的强制性与可选扩展。强制性扩展编码为"m"属性的值(见第 7 节中 reserved-mext 的 ABNF)。可选扩展使用尚未分配的属姓名。
一端发送但另一端不理解的强制性扩展必须导致认证失败(服务器应发送"extensions-not-supported"这一 server-error-value)。
收到的未知可选扩展必须被忽略。
5.2. 与 SASL 机制要求的符合性
本节描述与 [RFC4422] 第 5 节规定的 SASL 机制要求的符合性。
- "SCRAM-SHA-1"与"SCRAM-SHA-1-PLUS"。
- 2a)SCRAM 是一种客户端首发的机制。
- 2b)SCRAM 在成功时发送附加数据。
- SCRAM 能够将授权标识从客户端传送到服务器。
- SCRAM 不提供任何安全层(SCRAM 以信道绑定替代之)。
- SCRAM 具有保护授权标识的哈希。
6. 信道绑定
SCRAM 支持对外部安全信道(如 TLS)的信道绑定。客户端与服务器可能支持也可能不支持信道绑定,因此信道绑定的使用是可协商的。然而,SCRAM 不提供安全层,因此 SCRAM 必须为信道绑定的协商提供完整性保护。
信道绑定的使用按如下方式协商:
- 支持信道绑定使用的服务器应同时通告非 PLUS(SCRAM-<hash-function>)与 PLUS 变体(SCRAM-<hash-function>-PLUS)的机制名。如果服务器无法支持信道绑定,它应仅通告非 PLUS 变体。如果服务器由于策略原因永远不可能使非 PLUS 变体认证成功,它必须仅通告 PLUS 变体。
- 如果客户端支持信道绑定而服务器看起来不支持(即客户端未看到服务器通告的 -PLUS 名称),则客户端不得使用"n"这一 gs2-cbind-flag。
- 支持机制协商与信道绑定的客户端,在服务器提供所需 GS2 机制的 PLUS 变体时,必须使用"p"这一 gs2-cbind-flag。
- 如果客户端不支持信道绑定,则它必须使用"n"这一 gs2-cbind-flag。反之,如果客户端要求使用信道绑定,则它必须使用"p"这一 gs2-cbind-flag。不支持机制协商的客户端绝不使用"y"这一 gs2-cbind-flag,而是根据它们是否要求并支持信道绑定的使用,分别使用"p"或"n"。
- 收到客户端首条消息后,服务器检查信道绑定标志(gs2-cbind-flag)。
- 如果该标志被置为"y"且服务器支持信道绑定,服务器必须使认证失败。这是因为,如果客户端将信道绑定标志置为"y",那么客户端必定认为服务器不支持信道绑定——而如果服务器事实上支持信道绑定,这就表明发生了降级攻击(例如攻击者更改了服务器的机制列表,将带 -PLUS 后缀的 SCRAM 机制名排除在外)。
- 如果信道绑定标志为"p"而服务器不支持所指明的信道绑定类型,则服务器必须使认证失败。
服务器必须始终验证客户端的"c="字段。服务器通过构造"c="属性的值,然后检查它是否与客户端的 c= 属性值匹配来做到这一点。
关于信道绑定的更多讨论,以及各种安全协议信道绑定数据的语法,见 [RFC5056]。
6.1. 默认信道绑定
对于未自行提供信道绑定类型协商的所有 SASL 应用协议,提供如下默认信道绑定类型协商过程。
"tls-unique"是任何未指定信道绑定类型的应用的默认信道绑定类型。
如果服务器实现了任何信道绑定,则必须实现"tls-unique" [RFC5929] 信道绑定类型。如果客户端实现了任何信道绑定,则应该实现"tls-unique" [RFC5929] 信道绑定类型。客户端与服务器应选择最高层/最内层端到端的 TLS 信道作为要绑定的信道。
服务器必须选择客户端所指明的信道绑定类型,若不支持则使认证失败。
7. 形式化语法
下列语法规范使用 [RFC5234] 规定的增广巴科斯-瑙尔范式(ABNF)记法。"UTF8-2"、"UTF8-3"与"UTF8-4"这些非终结符定义于 [RFC3629]。
ALPHA = <as defined in RFC 5234 appendix B.1>
DIGIT = <as defined in RFC 5234 appendix B.1>
UTF8-2 = <as defined in RFC 3629 (STD 63)>
UTF8-3 = <as defined in RFC 3629 (STD 63)>
UTF8-4 = <as defined in RFC 3629 (STD 63)>
attr-val = ALPHA "=" value
;; Generic syntax of any attribute sent
;; by server or client
value = 1*value-char
value-safe-char = %x01-2B / %x2D-3C / %x3E-7F /
UTF8-2 / UTF8-3 / UTF8-4
;; UTF8-char except NUL, "=", and ",".
value-char = value-safe-char / "="
printable = %x21-2B / %x2D-7E
;; Printable ASCII except ",".
;; Note that any "printable" is also
;; a valid "value".
base64-char = ALPHA / DIGIT / "/" / "+"
base64-4 = 4base64-char
base64-3 = 3base64-char "="
base64-2 = 2base64-char "=="
base64 = *base64-4 [base64-3 / base64-2]
posit-number = %x31-39 *DIGIT
;; A positive number.
saslname = 1*(value-safe-char / "=2C" / "=3D")
;; Conforms to <value>.
authzid = "a=" saslname
;; Protocol specific.
cb-name = 1*(ALPHA / DIGIT / "." / "-")
;; See RFC 5056, Section 7.
;; E.g., "tls-server-end-point" or
;; "tls-unique".
gs2-cbind-flag = ("p=" cb-name) / "n" / "y"
;; "n" -> client doesn't support channel binding.
;; "y" -> client does support channel binding
;; but thinks the server does not.
;; "p" -> client requires channel binding.
;; The selected channel binding follows "p=".
gs2-header = gs2-cbind-flag "," [ authzid ] ","
;; GS2 header for SCRAM
;; (the actual GS2 header includes an optional
;; flag to indicate that the GSS mechanism is not
;; "standard", but since SCRAM is "standard", we
;; don't include that flag).
username = "n=" saslname
;; Usernames are prepared using SASLprep.
reserved-mext = "m=" 1*(value-char)
;; Reserved for signaling mandatory extensions.
;; The exact syntax will be defined in
;; the future.
channel-binding = "c=" base64
;; base64 encoding of cbind-input.
proof = "p=" base64
nonce = "r=" c-nonce [s-nonce]
;; Second part provided by server.
c-nonce = printable
s-nonce = printable
salt = "s=" base64
verifier = "v=" base64
;; base-64 encoded ServerSignature.
iteration-count = "i=" posit-number
;; A positive number.
client-first-message-bare =
[reserved-mext ","]
username "," nonce ["," extensions]
client-first-message =
gs2-header client-first-message-bare
server-first-message =
[reserved-mext ","] nonce "," salt ","
iteration-count ["," extensions]
client-final-message-without-proof =
channel-binding "," nonce [","
extensions]
client-final-message =
client-final-message-without-proof "," proof
server-error = "e=" server-error-value
server-error-value = "invalid-encoding" /
"extensions-not-supported" / ; unrecognized 'm' value
"invalid-proof" /
"channel-bindings-dont-match" /
"server-does-support-channel-binding" /
; server does not support channel binding
"channel-binding-not-supported" /
"unsupported-channel-binding-type" /
"unknown-user" /
"invalid-username-encoding" /
; invalid username encoding (invalid UTF-8 or
; SASLprep failed)
"no-resources" /
"other-error" /
server-error-value-ext
; Unrecognized errors should be treated as "other-error".
; In order to prevent information disclosure, the server
; may substitute the real reason with "other-error".
server-error-value-ext = value
; Additional error reasons added by extensions
; to this document.
server-final-message = (server-error / verifier)
["," extensions]
extensions = attr-val *("," attr-val)
;; All extensions are optional,
;; i.e., unrecognized attributes
;; not defined in this document
;; MUST be ignored.
cbind-data = 1*OCTET
cbind-input = gs2-header [ cbind-data ]
;; cbind-data MUST be present for
;; gs2-cbind-flag of "p" and MUST be absent
;; for "y" or "n".
8. SCRAM 作为 GSS-API 机制
本节及其子节、以及本文档其他位置未引用的本节所有规范性参考,对于 SASL 实现者而言是资料性(INFORMATIONAL)的,但对于 GSS-API 实现者而言是规范性(NORMATIVE)的。
SCRAM 实际上也是一种 GSS-API 机制。消息是相同的,但(a)当 SCRAM 作为 GSS-API 机制使用时,客户端首条消息上的 GS2 头与信道绑定数据被排除在外,且(b)RFC2743 第 3.1 节的初始上下文令牌头被前缀到客户端的首条认证消息(上下文令牌)之前。
用于 SCRAM-SHA-1 的 GSS-API 机制 OID 为 1.3.6.1.5.5.14(见第 10 节)。
SCRAM 安全上下文的 mutual_state 标志(GSS_C_MUTUAL_FLAG)总是被置为 TRUE。SCRAM 不支持凭据委派(credential delegation),因此 SCRAM 安全上下文的 deleg_state 标志(GSS_C_DELEG_FLAG)总是被置为 FALSE。
8.1. 适用于 SCRAM 的 GSS-API 主体名称类型
SCRAM 并不显式命名接受方(acceptor)主体。然而,使用接受方主体名称来查找或提示输入口令是有用的。因此,SCRAM 支持标准的通用名称语法用于接受方,例如 GSS_C_NT_HOSTBASED_SERVICE(见 [RFC2743] 第 4.1 节)。实现应使用传入 GSS_Init_sec_context() 的目标名称(如果有的话)来帮助检索或提示输入 SCRAM 口令。
SCRAM 仅支持发起方(initiator)的单一名称类型:GSS_C_NT_USER_NAME。GSS_C_NT_USER_NAME 是 SCRAM 的默认名称类型。
除第 5.1 节描述的 SASLprep 应用之外,SCRAM 没有名称规范化过程。
SCRAM 主体名称的查询、显示与导出名称语法都是相同的。没有 SCRAM 特定的名称语法(SCRAM 发起方主体名称是自由格式);应用应使用通用的 GSS-API 名称类型,如 GSS_C_NT_USER_NAME 与 GSS_C_NT_HOSTBASED_SERVICE(见 [RFC2743] 第 4 节)。当然,导出的名称令牌符合 [RFC2743] 第 3.2 节,但令牌的"NAME"部分只是一个 SCRAM 用户名。
8.2. 适用于 SCRAM 的 GSS-API 逐消息令牌
作为 GSS-API 机制的 SCRAM 的逐消息令牌,应与 Kerberos V 的 GSS-API 机制 [RFC4121] 的逐消息令牌相同(见第 4.2 节及其子节),使用 Kerberos V 的"aes128-cts-hmac-sha1-96"加密类型 [RFC3962]。
replay_det_state(GSS_C_REPLAY_FLAG)、sequence_state(GSS_C_SEQUENCE_FLAG)、conf_avail(GSS_C_CONF_FLAG)与 integ_avail(GSS_C_CONF_FLAG)这些安全上下文标志总是被置为 TRUE。
128 位的会话"协议密钥(protocol key)"应通过使用 HMAC(StoredKey, "GSS-API session key" || ClientKey || AuthMessage) 最不显著(最右侧)的 128 位来派生。"特定密钥(specific keys)"随后按 [RFC4121]、[RFC3961] 与 [RFC3962] 第 2 节的通常方式派生。
"protocol key"与"specific key"是 Kerberos V5 的术语 [RFC3961]。
SCRAM 支持 PROT_READY,并且在发起方一侧,于收到服务器对初始安全上下文令牌的应答时首先进入 PROT_READY 状态。
8.3. 适用于 SCRAM 的 GSS_Pseudo_random()
SCRAM 的 GSS_Pseudo_random() [RFC4401] 应与 Kerberos V 的 GSS-API 机制 [RFC4402] 相同。SCRAM 没有接受方断言的子会话密钥,因此对于 SCRAM 的 GSS_Pseudo_random() 而言,GSS_C_PRF_KEY_FULL 与 GSS_C_PRF_KEY_PARTIAL 是等价的。用于 GSS_Pseudo_random() 的协议密钥应与第 8.2 节定义的密钥相同。
9. 安全考量
如果认证交换是在没有强安全层(如具有数据保密性的 TLS)的情况下进行的,那么被动窃听者可以获得足够信息,发起离线的字典攻击或暴力破解攻击,从而恢复用户的口令。该攻击所需的时间取决于所选的密码学哈希函数、口令的强度以及服务器提供的迭代数。具有强加密的外部安全层将阻止此类攻击。
如果用于保护 SCRAM 交换的外部安全层使用了匿名密钥交换,那么 SCRAM 信道绑定机制可用于检测对安全层的中间人攻击,并由此导致认证失败。然而,中间人攻击者已经获得足够信息来发起离线字典攻击或暴力破解攻击。为此,SCRAM 允许随着时间推移提高迭代数。(注意,仅持有"StoredKey"和"ServerKey"的服务器无法在成功认证后自动提高迭代数。这种提高需要重置用户的口令。)
如果认证信息从认证数据库中被盗,那么可以发起离线字典攻击或暴力破解攻击来恢复用户的口令。盐的使用在一定程度上缓解了此攻击,因为它要求对每个口令分别发起攻击。能够抵御此类攻击的认证机制是存在的(例如 EKE 类机制)。RFC 2945 [RFC2945] 就是此类技术的一个例子。工作组选择不以 EKE 类机制作为 SCRAM 的基础。
如果攻击者从认证信息库中获取了认证信息,并窃听某次认证交换或冒充服务器,该攻击者就获得了冒充该用户去对付所有使用相同哈希函数、口令、迭代数与盐、提供 SCRAM 访问的服务器的能力。因此,使用随机生成的盐值十分重要。
SCRAM 不协商要使用的哈希函数。哈希函数的协商留给 SASL 机制协商处理。重要的是,客户端必须能够对本地可用的机制列表按偏好排序,以便客户端可以从服务器通告的机制列表中挑选合适的机制使用。此偏好顺序此处未做规定,因为它属于本地事务。偏好顺序应同时包含机制密码学强度的客观与主观评判(例如,使用 SHA-1 后继者的 SCRAM 可能优先于使用 SHA-1 的 SCRAM)。
注意,为保护 SASL 机制协商,应用通常必须两次列出服务器机制:一次在认证之前,一次在认证之后(后者使用安全层)。由于 SCRAM 不提供安全层,保护机制协商的唯一方式是(a)对外部信道使用信道绑定,或(b)使用对用户提供服务器名进行认证的外部信道。
SCRAM 不抵御信道绑定类型的降级攻击。协商信道绑定类型、以及在该协商中处理降级攻击的复杂性,被有意排除在本文档范围之外。
恶意服务器可以通过发送很大的迭代数值,对客户端发起计算性的拒绝服务攻击。
关于生成随机性的更多信息,见 [RFC4086]。
10. IANA 考量
IANA 已将从 [RFC4422] 建立的 SASL 机制注册表中新增的下列 SASL 机制系列加入:
To: iana@iana.org Subject: Registration of a new SASL family SCRAM SASL mechanism name (or prefix for the family): SCRAM-* Security considerations: Section 7 of [RFC5802] Published specification (optional, recommended): [RFC5802] Person & email address to contact for further information: IETF SASL WG <sasl@ietf.org> Intended usage: COMMON Owner/Change controller: IESG <iesg@ietf.org> Note: Members of this family MUST be explicitly registered using the "IETF Review" [RFC5226] registration procedure. Reviews MUST be requested on the SASL mailing list <sasl@ietf.org> (or a successor designated by the responsible Security AD).
给未来的 SCRAM 机制设计者的提示:每个新的 SCRAM-SASL 机制必须显式在 IANA 注册,并且必须符合本文档第 4 节定义的 SCRAM 机制命名约定。
IANA 已从 [RFC4422] 建立的 SASL 机制注册表中新增下列条目:
To: iana@iana.org Subject: Registration of a new SASL mechanism SCRAM-SHA-1 SASL mechanism name (or prefix for the family): SCRAM-SHA-1 Security considerations: Section 7 of [RFC5802] Published specification (optional, recommended): [RFC5802] Person & email address to contact for further information: IETF SASL WG <sasl@ietf.org> Intended usage: COMMON Owner/Change controller: IESG <iesg@ietf.org> Note:
To: iana@iana.org Subject: Registration of a new SASL mechanism SCRAM-SHA-1-PLUS SASL mechanism name (or prefix for the family): SCRAM-SHA-1-PLUS Security considerations: Section 7 of [RFC5802] Published specification (optional, recommended): [RFC5802] Person & email address to contact for further information: IETF SASL WG <sasl@ietf.org> Intended usage: COMMON Owner/Change controller: IESG <iesg@ietf.org> Note:
根据本文档,IANA 已从 iso.org.dod.internet.security.mechanisms 前缀(见"SMI Security for Mechanism Codes"注册表)中为 SCRAM-SHA-1 分配了一个 GSS-API 机制 OID。
11. 致谢
本文档得益于 SASL 工作组邮件列表上的讨论。作者特别感谢 Dave Cridland、Simon Josefsson、Jeffrey Hutzelman、Kurt Zeilenga、Pasi Eronen、Ben Campbell、Peter Saint-Andre 与 Tobias Markmann 对本文档的贡献。特别感谢 Simon Josefsson 对本文档的引导,以及完成了本规范最早的若干实现之一。
12. 参考文献
12.1. 规范性参考文献
- [RFC2104] Krawczyk, H., Bellare, M., and R. Canetti, "HMAC: Keyed-Hashing for Message Authentication", RFC 2104, February 1997.
- [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, March 1997.
- [RFC3174] Eastlake, D. and P. Jones, "US Secure Hash Algorithm 1 (SHA1)", RFC 3174, September 2001.
- [RFC3454] Hoffman, P. and M. Blanchet, "Preparation of Internationalized Strings ("stringprep")", RFC 3454, December 2002.
- [RFC3629] Yergeau, F., "UTF-8, a transformation format of ISO 10646", STD 63, RFC 3629, November 2003.
- [RFC4013] Zeilenga, K., "SASLprep: Stringprep Profile for User Names and Passwords", RFC 4013, February 2005.
- [RFC4422] Melnikov, A. and K. Zeilenga, "Simple Authentication and Security Layer (SASL)", RFC 4422, June 2006.
- [RFC4648] Josefsson, S., "The Base16, Base32, and Base64 Data Encodings", RFC 4648, October 2006.
- [RFC5056] Williams, N., "On the Use of Channel Bindings to Secure Channels", RFC 5056, November 2007.
- [RFC5234] Crocker, D. and P. Overell, "Augmented BNF for Syntax Specifications: ABNF", STD 68, RFC 5234, January 2008.
- [RFC5929] Altman, J., Williams, N., and L. Zhu, "Channel Bindings for TLS", RFC 5929, July 2010.
12.2. 面向 GSS-API 实现者的规范性参考文献
- [RFC2743] Linn, J., "Generic Security Service Application Program Interface Version 2, Update 1", RFC 2743, January 2000.
- [RFC3961] Raeburn, K., "Encryption and Checksum Specifications for Kerberos 5", RFC 3961, February 2005.
- [RFC3962] Raeburn, K., "Advanced Encryption Standard (AES) Encryption for Kerberos 5", RFC 3962, February 2005.
- [RFC4121] Zhu, L., Jaganathan, K., and S. Hartman, "The Kerberos Version 5 Generic Security Service Application Program Interface (GSS-API) Mechanism: Version 2", RFC 4121, July 2005.
- [RFC4401] Williams, N., "A Pseudo-Random Function (PRF) API Extension for the Generic Security Service Application Program Interface (GSS-API)", RFC 4401, February 2006.
- [RFC4402] Williams, N., "A Pseudo-Random Function (PRF) for the Kerberos V Generic Security Service Application Program Interface (GSS-API) Mechanism", RFC 4402, February 2006.
- [RFC5801] Josefsson, S. and N. Williams, "Using Generic Security Service Application Program Interface (GSS-API) Mechanisms in Simple Authentication and Security Layer (SASL): The GS2 Mechanism Family", RFC 5801, July 2010.
12.3. 资料性参考文献
- [CRAMHISTORIC] Zeilenga, K., "CRAM-MD5 to Historic", Work in Progress, November 2008.
- [DIGESTHISTORIC] Melnikov, A., "Moving DIGEST-MD5 to Historic", Work in Progress, July 2008.
- [RFC2865] Rigney, C., Willens, S., Rubens, A., and W. Simpson, "Remote Authentication Dial In User Service (RADIUS)", RFC 2865, June 2000.
- [RFC2898] Kaliski, B., "PKCS #5: Password-Based Cryptography Specification Version 2.0", RFC 2898, September 2000.
- [RFC2945] Wu, T., "The SRP Authentication and Key Exchange System", RFC 2945, September 2000.
- [RFC4086] Eastlake, D., Schiller, J., and S. Crocker, "Randomness Requirements for Security", BCP 106, RFC 4086, June 2005.
- [RFC4510] Zeilenga, K., "Lightweight Directory Access Protocol (LDAP): Technical Specification Road Map", RFC 4510, June 2006.
- [RFC4616] Zeilenga, K., "The PLAIN Simple Authentication and Security Layer (SASL) Mechanism", RFC 4616, August 2006.
- [RFC4949] Shirey, R., "Internet Security Glossary, Version 2", RFC 4949, August 2007.
- [RFC5226] Narten, T. and H. Alvestrand, "Guidelines for Writing an IANA Considerations Section in RFCs", BCP 26, RFC 5226, May 2008.
- [RFC5246] Dierks, T. and E. Rescorla, "The Transport Layer Security (TLS) Protocol Version 1.2", RFC 5246, August 2008.
- [RFC5803] Melnikov, A., "Lightweight Directory Access Protocol (LDAP) Schema for Storing Salted Challenge Response Authentication Mechanism (SCRAM) Secrets", RFC 5803, July 2010.
- [tls-server-end-point] IANA, "Registration of TLS server end-point channel bindings", available from http://www.iana.org, June 2008.
附录 A. 其他认证机制
DIGEST-MD5 [DIGESTHISTORIC] 机制已被证明过于复杂而难以实现与测试,因此互操作性很差。其安全层常常未实现,且几乎从不使用;每个人都改用 TLS。关于导致创建 SCRAM 的、DIGEST-MD5 的更完整问题列表,见 [DIGESTHISTORIC]。
CRAM-MD5 这一 SASL 机制虽被广泛部署,但也存在一些问题。特别是,它缺少一些现代 SASL 特性,例如对国际化用户名与口令的支持、对传递授权标识的支持,以及对信道绑定的支持。它也不支持服务器认证。关于 CRAM-MD5 更完整的问题列表,见 [CRAMHISTORIC]。
PLAIN [RFC4616] 这一 SASL 机制允许恶意服务器或窃听者冒充认证用户去对付该用户拥有相同口令的任何其他服务器。除非使用 TLS,否则它还在网络上以明文发送口令。它不支持服务器认证。
附录 B. 设计动机
以下设计目标塑造了本文档。注意,其中一些目标自文档初始版本以来已经改变。
- 该 SASL 机制具备所有现代 SASL 特性:支持国际化用户名与口令、支持传递授权标识、支持信道绑定。
- 该协议支持双向认证。
- 存储在认证数据库中的认证信息本身不足以冒充客户端。
- 服务器无法获得冒充客户端去对付其他服务器的能力(经服务器授权的代理除外),除非那些其他服务器允许 SCRAM 认证,并对该用户使用相同的盐与迭代数。
- 该机制是可扩展的,但(希望)在这方面并未过度设计。
- 该机制在客户端与服务器上都比 DIGEST-MD5 更易于实现。
作者地址
Chris Newman
Oracle
800 Royal Oaks
Monrovia, CA 91016
USA
EMail: chris.newman@oracle.com
Abhijit Menon-Sen
Oryx Mail Systems GmbH
EMail: ams@toroid.org
Alexey Melnikov
Isode, Ltd.
EMail: Alexey.Melnikov@isode.com
Nicolas Williams
Oracle
5300 Riata Trace Ct
Austin, TX 78727
USA
EMail: Nicolas.Williams@oracle.com
