记录了openfire 用户注册过程(如图)
1、客户端发送注册iq节到服务器;
2、服务器接收iq节并解析iq节;
3、调用加密流程对用户的密码进行加密
4、把加密后的密码保存到数据库。
STARTTLS协商
STARTTLS基础
XMPP包含了一个方法来保护流的安全使其免于被篡改和. 这个通道加密的方法使用传输层安全TLS协议, 特别是"STARTTLS"扩展,这个扩展是以USINGTLS中描述的IMAP,POP3, 和ACAP协议中的类似扩展为蓝本的. STARTTLS扩展的XML命名空间是 'urn:ietf:params:xml:ns:xmpp-tls'.
支持
在XMPP客户端和服务器的实现中必须支持STARTTLS. 一个给定布署的管理员可以指定 客户端-服务器通讯 和/或 服务器-服务器通讯 中TLS是强制协商的. 一个初始化实体应该在开始SASL验证之前使用TLS保护和接收方之间的流的安全.
流协商规则
强制协商
如果接收方实体只声明了STARTTLS特性或接收方实体包含了5.4.1所述的<required/>子元素, 双方必须确保TLS是强制协商的. 如果TLS是强制协商的, 在流协商过程的初始化阶段接收方实体应该不(SHOULD NOT)声明支持任何STARTTLS以外的流特性, 因为在XMPP的层顺序中更多流特性可能依赖TLS的预先协商 (例如, 由接收方实体提供的特定的SASL机制将依赖于TLS是否完成协商).
重启
在TLS协商之后, 双方必须重启这个流.
数据格式
当STARTTLS协商时, 实体们不能(MUST NOT)在XML元素之间发送任何空格符号 (即, 由初始化实体发送的从'urn:ietf:params:xml:ns:xmpp-tls'命名空间限定的顶级<starttls/>元素的最后的字符, 到由接收方实体发送的'urn:ietf:params:xml:ns:xmpp-tls'命名空间限定的顶级<proceed/>元素的最后的字符). 这个禁令帮助确保适当的安全字节精度. 任何出现在本文提供的STARTTLS例子中的空格只是为了提高可读性.
TLS和SASL协商的顺序
如果初始化实体选择使用TLS, STARTTLS协商必须在SASL协商之前完成; 这个协商顺序对于帮助保护SASL协商期间发送的验证信息是必要的, 同时尽可能使用基于预先的TLS协商中提供的证书(或其他证件)的SASL EXTERNAL机制.
TLS重协商
TLS协议允许双方在一个 受TLS保护 的通道里初始化一个新的握手来建立新的加密参数(见TLS‑NEG). 最常提及的案例如下:
- 刷新密钥
- 如TLS的6.1节所述封装TLS序列号.
- 在受保护的通道上先完成服务器验证再完成客户端验证以保护客户端证书.
因为在XMPP中建立一个流的代价相对低廉, 对于前面两个案例推荐使用XMPP流重置(如4.9.3.16) 而不是执行TLS重协商.
第三个案例在TLS客户端(也可能是一个XMPP服务器)递交TLS证书给服务器时提高了安全特性. 如果和一个未验证的TLS服务器交换这类证书可能泄露隐私信息, 先完成让TLS客户端验证TLS服务器的TLS协商,再完成让TLS服务器验证TLS客户端的TLS协商,是适当的. 然而, 这个案例极为罕见,因为由一个扮演TLS客户端角色的XMPP服务器或XMPP客户端对外展现的证书几乎总是公开的(即, PKIX 证书), 所以在验证作为TLS服务器的XMPP服务器之前提供那些证书通常将不会泄露隐私信息.
作为结果, 鼓励实现者在他们的软件中支持TLS重协商之前小心地权衡它的开销和好处, 不鼓励扮演TLS客户端的XMPP实体尝试TLS重协商,除非已知要在TLS协商中发送的证书(或其他证件信息)是私有的.
对TLS重协商的支持是严格可选的. 然而, 支持TLS重协商的实现们必须实现和使用 TLS重协商扩展TLS‑NEG.
如果一个不支持TLS重协商的实体察觉到一个重协商尝试, 那么它必须立刻关闭相关的TCP连接而不要返回任何流错误(因为这个违规可能发生在TLS层, 而不是XMPP层, 详见13.3).
如果一个支持TLS重协商的实体察觉到一个未使用 TLS重协商扩展TLS‑NEG的TLS重协商尝试 , 那么它必须立刻关闭相关的TCP连接而不要返回任何流错误(因为这个违规可能发生在TLS层, 而不是XMPP层, 详见13.3).
TLS扩展
一个流的双方可以在它自己的TLS协商时包含任何TLS扩展. 这是TLS层的事情, 不是XMPP层.
过程
流头和流特性交换
初始化实体如第三章所述解析接收实体的合格域名(FQDN), 打开一个到解析的IP地址和声明的端口的TCP连接, 并发送一个初始化流头给接收方流头.
I: <stream:stream from='juliet@im.example.com' to='im.example.com' version='1.0' xml:lang='en' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'>
接收方实体必须通过初始化实体打开的那个TCP连接发送一个应答流头给初始化实体.
R: <stream:stream from='im.example.com' id='t7AMCin9zjMNwQKDnplntZPIDEI=' to='juliet@im.example.com' version='1.0' xml:lang='en' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'>
接着接收方实体必须发送流特性给初始化实体. 如果接收方实体支持TLS, 流特性必须包含一个支持STARTTLS协商的声明, 即, 一个由'urn:ietf:params:xml:ns:xmpp-tls'命名空间限定的<starttls/>元素.
如果接收方实体认为STARTTLS协商是强制协商的, <starttls/>元素必须包含一个空的<required/>子元素.
R: <stream:features> <starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'> <required/> </starttls> </stream:features>
STARTTLS协商的初始化
STARTTLS命令
为了开始STARTTLS协商, 初始化实体发出STARTTLS指令(即, 一个由'urn:ietf:params:xml:ns:xmpp-tls'命名空间限定的<starttls/>元素)来指示接收方实体它希望开始一次STARTTLS协商以保护流.
I: <starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>
接收方实体必须以由'urn:ietf:params:xml:ns:xmpp-tls'命名空间限定的<proceed/>元素(继续进行的情况下)或<failure/>元素(失败的情况下)回复.
失败的情况
如果发生失败的情况, 接收方实体必须返回一个由'urn:ietf:params:xml:ns:xmpp-tls'命名空间限定的<failure/>元素, 关闭这个XML流, 并且终止当前的TCP连接.
R: <failure xmlns='urn:ietf:params:xml:ns:xmpp-tls'/> R: </stream:stream>
导致失败的情况包含但不限于以下几种:
-
- 初始化实体发送了一个异常的STARTTLS命令.
- 接收方实体在它的流特性中不提供STARTTLS特性 .
- 接收方实体因为内部错误而无法完成STARTTLS协商.
- 提示性备注: STARTTLS失败不会由TLS错误触发,例如 坏证书(bad_certificate)或 握手失败(handshake_failure), 它是由TLS协商本身生成和处理的,参见 TLS.
如果发生了失败的情况, 初始化实体可以尝试重连,参见3.3.
继续进行的情况
如果发生继续进行的情况, 接收方实体必须返回一个由'urn:ietf:params:xml:ns:xmpp-tls'命名空间限定的<proceed/>元素.
R: <proceed xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>
接收方实体在发送了<proceed/>元素的关闭字符'>'之后必须认为TLS协商已经立刻开始了. 初始化实体在从接收方实体接收到<proceed/>元素的关闭字符'>'之后必须认为TLS协商已经立刻开始了.
实体现在继续进行TLS协商,如下一节所述.
TLS协商
规则
为了在TCP连接上完成TLS协商, 实体们必须跟随以下定义于TLS的过程 .
以下规则适用于:
-
- 实体们在TLS协商完成之前不能(MUST NOT)发送任何其他XML数据.
- 当使用定义于13.8的任何强制实现(MTI)的密码组时, 接收方实体必须出示一个证书.
- 所以证书相互验证是有可能的, 接收方实体应该发送一个证书请求给初始化实体, 而初始化实体应该发送一个证书给接收方实体(但是由于隐私的原因可能选择在接收方实体已经被初始化实体验证之后才发送自己的证书).
- 接收方实体应该基于包含在初始化流头中的'to'属性中的域部分选择哪个证书来展示(本质上, 这个域部分功能上等同于服务器名称指示 定义于TLS‑EXT).
- 为了确定TLS协商是否成功, 初始化实体必须尝试根据13.7.2定义的证书验证程序来验证接收方实体的证书.
- 如果初始化实体出示了一个证书, 接收方实体也必须尝试根据13.7.2定义的证书验证程序来验证初始化实体的证书.
- 随着TLS协商成功, 所有双方传送的更多的数据必须被协商的算法,密钥和秘密来保护(即, 加密, 完整性保护, 或都依赖于使用的密码组).
- 安全警告: 关于 13.8提到的密码组必须被TLS所支持; 自然的, 其他密码组也可以被支持.
TLS失败
如果TLS协商结果是失败, 接收方实体必须终止该TCP连接.
在终止该TCP连接之前,接收方实体不能(MUST NOT)发送关闭标签</stream>(因为失败可能发生在TLS层, 而不是XMPP层,参见13.3所述).
初始化实体可以如3.3所述尝试重连, 尝试使用或不使用TLS协商(依照本地服务策略, 用户配置的偏好, 等等).
TLS成功
如果TLS协商是成功的, 那么实体们必须继续如下步骤.
- 1. 初始化实体必须忽略TLS生效之前在TCP上的不安全情况下从接收方实体收到的任何信息(例如, 接收方实体的'from'地址或从接收方实体收到的流ID以及流特性).
- 2. 接收方实体必须忽略TLS生效之前在TCP上的不安全情况下从初始化实体收到的任何信息(例如, 初始化实体的'from'地址).
- 3. 初始化实体必须通过加密的连接发送一个新的初始化流头给接收方实体(如 4.3.3定义的, 在发送新的初始化流头之前初始化实体必须发送一个关闭标签</stream>, 因为接收方实体和初始化实体必须确定旧的流在TLS协商成功之后被替代了).
I: <stream:stream from='juliet@im.example.com' to='im.example.com' version='1.0' xml:lang='en' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'>
- 4. 接收方实体必须通过加密连接以一个新的应答流头来应答(为此它必须生成一个新的流ID而不是重用旧的流ID).
R: <stream:stream from='im.example.com' id='vgKi/bkYME8OAj4rlXMkpucAqe4=' to='juliet@im.example.com' version='1.0' xml:lang='en' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'>
- 5. 接收方实体也必须发送流特性给初始化实体, 不能(MUST NOT)包含STARTTLS特性但是应该包含SASL流特性,如 第六章(特别是 6.4.1中关于为什么不在这里提供SASL流特性的新的原因).
R: <stream:features> <mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'> <mechanism>EXTERNAL</mechanism> <mechanism>SCRAM-SHA-1-PLUS</mechanism> <mechanism>SCRAM-SHA-1</mechanism> <mechanism>PLAIN</mechanism> </mechanisms> </stream:features>
SASL协商
SASL基础
XMPP包含了一个某种意义上XMPP特有的简单验证和安全层协议(见SASL)用于验证一个流. SASL提供一个一般化的方法来给基于连接的协议添加验证支持, 而XMPP遵照SASL的解析要求来使用SASL的XML命名空间解析. SASL扩展的XML命名空间名称是'urn:ietf:params:xml:ns:xmpp-sasl'.
支持
XMPP客户端和服务器必须支持SASL协商.
流协商规则
强制协商
一个流双方bxu确认SASL是强制协商的.
重启
在SASL协商之后, 双方必须重启该流.
机制推荐
任何将要扮演SASL客户端或SASL服务器的实体必须对于该客户端或该服务器维护一个它推荐的SASL机制的有序列表, 这个列表的顺序是根据本地策略或用户配置来的(它的顺序应该是根据验证能力越强排在越靠前). 初始化实体必须独立于接收方实体的推荐顺序来维护它自己的推荐顺序. 客户端必须以它自己的推荐顺序来尝试SASL机制. 例如, 如果服务器提供的顺序列表是"PLAIN SCRAM-SHA-1 GSSAPI" 或 "SCRAM-SHA-1 GSSAPI PLAIN" 而客户端的顺序列表是 "GSSAPI SCRAM-SHA-1", 客户端必须首先尝试 GSSAPI 然后尝试 SCRAM-SHA-1 而不能(MUST NOT)尝试 PLAIN (因为 PLAIN 不在它的列表中).
机制提供
如果接收方实体在它接受特定的SASL机制之前确定TLS协商是强制协商, 它不能(MUST NOT)在完成TLS协商之前在它的可用SASL机制列表中声明那个机制.
如果发生以下两种情况,接收方实体应该提供 SASL EXTERNAL 机制,:
-
- 当初始化实体在TLS协商中出示了一个证书,这个证书被接收方实体接受了,接收方根据本地服务策略把它用于强身份验证(例如, 因为证书没有过期,没有撤销,并且被锚定到一个接收方实体信任的root账户).
- 接收方实体期望初始化实体能够验证和授权这个证书所提供的身份; 在服务器-服务器流的情形下, 接收方实体可能有这样一个预期,因为初始化实体的证书所展示的DNS域名和初始化流头中相应的'from'属性是匹配的, 这里使用TLS‑CERTS的匹配规则; 在客户端-服务器流的情形下, 接收方实体可能有这样一个预期,是因为在初始化实体的证书中展示的纯JID和在这个服务器上注册的一个用户帐号匹配,或者因为其他包含在初始化实体证书中的信息和被允许使用该服务器访问XMPP网络的某个实体相匹配.
无论如何, 接收方实体在其他情况下也一样可以提供 SASL EXTERNAL 机制.
当接收方实体提供 SASL EXTERNAL 机制, 接收方实体应该首先列出它提供的SASL机制的 EXTERNAL 机制列表,而初始化实体应该尝试首先使用EXTERNAL机制来进行SASL协商(这个选择往往会增加双方相互进行证书验证的可能性).
13.8定义了必须支持的SASL机制; 自然的, 也一样可以支持其他的SASL机制.
数据格式
以下数据格式规则适用于SASL协商:
-
- 当SASL协商时, 实体不能(MUST NOT)在XML元素之间发送任何空格符号(即, 从初始化实体发送的'urn:ietf:params:xml:ns:xmpp-sasl'命名空间限定的<auth/>顶级元素的最后一个字符, 到接收方实体发送的'urn:ietf:params:xml:ns:xmpp-sasl'命名空间限定的<success/>顶级元素的最后一个字符). 这个禁令帮助确保正确的安全层字节精确度. 本文中任何在SASL例子中出现的这类空格只是为了增加可读性.
- 任何包含在XML元素中的XML字符串数据必须使用base 64编码, 这里的编码要坚持BASE64第四章的定义,并且填充位设为零.
- 作为附录A.4下的XML schema中正式指定的 'urn:ietf:params:xml:ns:xmpp-sasl' 命名空间, 接收方实体可以在<mechanisms/>元素中包含一个或多个应用特有的子元素来提供初始化实体使用提供的一个或多个机制进行成功的SASL协商而可能需要的信息; 无论如何, 所有这类元素的语法和语义超出了本协议的范围(见XEP‑0233的例子).
安全层
涉及安全层协商的SASL协商成功后, 初始化实体和接收方实体都必须丢弃任何应用层状态(即, 来自XMPP层的状态, 不包括来自TLS协商或SASL协商的状态).
简单用户名
一些SASL机制(例如, CRAM-MD5, DIGEST-MD5, 和 SCRAM) 指定了在这些机制的上下文中使用的验证身份是一个"简单用户名" (见SASL的第二章以及SASLPREP). 在任何特定的机制或部署中简单用户名的准确格式都是一个本地事务, 并且简单用户名不需要映射到一个应用身份例如JID或JID部件(例如, 本地部分). 无论如何, 在缺乏由服务器提供的本地信息的情况下, 一个XMPP客户端应该假定一个SASL机制的验证身份是等于该用户的JID的本地部分的简单用户名.
授权身份
授权身份是一个由初始化实体提供的可选的身份,用来定义它扮演的身份(见SASL第二章). 在客户端-服务器流中, 它大部分被管理员用于代表另一个用户来执行一些管理任务, 而在服务器-服务器流它大部分被用于在XMPP服务上指定一个特定的附加服务(例如, 一个多用户聊天服务器conference.example.com寄宿在example.com的XMPP服务上). 如果初始化实体希望代表另一个实体并且所选择的SASL机制支持授权身份的传输, 该初始化实体必须在SASL协商时提供一个授权身份. 如果初始化实体不希望代表另一个实体的身份, 它不能(MUST NOT)提供授权身份.
在客户端-服务器通讯的情况下, 授权身份的值必须是一个纯JID(<本地部分@域部分>) 而不是一个全JID(<本地部分@域部分/资源部分>).
在服务器-服务器通讯的情况下, 授权身份的值必须且只能是一个域部分(<域部分>).
如果初始化实体在SASL协商时提供一个授权身份, 接收方实体负责验证初始化实体是否事实上被允许承担指定的授权身份; 如果不是, 接收方实体必须返回一个<invalid-authzid/> SASL错误,如6.5.6所述.
领域
在以特定SASL机制协商的时候接受方实体可以包含一个领域(例如, GSSAPI 和 DIGEST-MD5 机制都允许验证交换的信息中包含领域, 不过其他方式, 如 EXTERNAL, SCRAM, 和 PLAIN 机制不支持这个特性). 如果接受方实体不以一个领域来通讯, 则初始化实体不能(MUST NOT)假定任何领域的存在. 领域必须只被用于验证的目的; 特别是, 初始化实体不能(MUST NOT)尝试从接受方实体提供的领域信息来派生出一个XMPP域部分.
回合
SASL规定,一个使用中的协议(例如XMPP)可以定义两个方法,这样协议可以节省批准SASL机制的回合:
-
- 当SASL客户端(XMPP "初始化实体") 请求一个验证交换时, 如果使用了适当的SASL机制,它可以在它的请求中包含 "初始化应答" 数据. 在XMPP中, 要实现这一点,就把初始化应答作为XML字符串数据包含在<auth/>元素中.
- 在验证交换的结尾, 如果使用了适当的SASL机制,SASL服务器(XMPP "接受方实体") 可以包含 "成功附带的额外数据". 在XMPP中, 要实现这一点,就把额外数据作为XML字符串数据包含在<success/>元素中.
为了协议的效率, 要求客户端和服务器必须支持这些方法并且建议使用它们; 无论如何, 客户端和服务器也必须支持低效的模式.
过程
SASL协商过程如下.
流头和流特性交换
如果SASL协商紧跟在成功的STARTTLS协商之后, 那么SASL协商发生在已经协商过的受保护的流上. 否则, 初始化实体如第三章所述解析接受方实体的完整域名(FQDN), 打开一个到已解析的IP地址的已声明的端口的TCP连接, 并发送一个初始化流头给接受方实体. 在两种情况下, 接受方实体都将从初始化实体接收到一个初始化流.
I: <stream:stream from='juliet@im.example.com' to='im.example.com' version='1.0' xml:lang='en' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'>
当接受方实体处理来自初始化实体的初始化流的时候, 它必须发送一个应答流头给初始化实体(为此它必须生成一个唯一的流ID. 如果TLS协商已经成功, 那么这个流ID必须不同于TLS协商成功之前发送的那个流ID).
R: <stream:stream from='im.example.com' id='vgKi/bkYME8OAj4rlXMkpucAqe4=' to='juliet@im.example.com' version='1.0' xml:lang='en' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'>
接受方实体也必须发送流特性给初始化实体. 流特性应该包含一个声明用来支持SASL协商, 即, 一个由'urn:ietf:params:xml:ns:xmpp-sasl'命名空间限定的<mechanisms/>元素. 典型的,只有三种情况下对SASL协商的支持不需要在这里声明:
-
- TLS协商需要在提供SASL之前发生(即, TLS是必需的并且接受方实体已经在接收到的这次连接尝试的初次的初始化流头中应答过了).
- SASL协商不可能发生在一个 服务器-服务器 连接中(即, 初始化服务器未提供一个证书以进行验证并且因而接受方实体回滚到使用服务器回拨协议XEP‑0220进行弱身份验证).
- SASL已经协商过了(即, 接受方实体在成功进行SASL协商之后应答一个以流重启的方式发送的初始化流头).
<mechanisms/>元素必须为接受方实体提供给初始化实体的每个验证机制包含一个<mechanism/>子元素. 大家知道, 在XML中的<mechanism/>元素的顺序表示来自接受方实体的SASL机制的优先顺序(它不一定是来自初始化实体的优先顺序).
R: <stream:features> <mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'> <mechanism>EXTERNAL</mechanism> <mechanism>SCRAM-SHA-1-PLUS</mechanism> <mechanism>SCRAM-SHA-1</mechanism> <mechanism>PLAIN</mechanism> </mechanisms> </stream:features>
初始化
为了开始SASL协商, 初始化实体发送一个由'urn:ietf:params:xml:ns:xmpp-sasl'命名空间限定的<auth/>元素并在'mechanism'属性包含一个适当的值, 从而开始使用特定的验证机制进行握手. 这个元素可以包含XML字符串数据(用SASL术语来说, 就是"初始化应答"),如果这个机制支持或必须要它的话. 如果初始化实体需要发送一个长度为零的初始化应答, 它必须以单个等号字符("=")来传输这个应答, 这表示那个应答是当前的但是不包含数据.
I: <auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='PLAIN'>AGp1bGlldAByMG0zMG15cjBtMzA=</auth>
如果初始化实体后来发送另一个<auth/>元素而正在进行的验证握手还没完成, 接收方实体必须丢弃正在进行的握手而必须为后来请求的SASL机制处理新的握手.
挑战-应答序列
如果必要, 接收方实体通过发送一个由'urn:ietf:params:xml:ns:xmpp-sasl'命名空间限定的<challenge/>元素来挑战初始化实体; 这个元素可以包含XML字符串数据(它必须根据被初始化实体选择的SASL机制的定义来生成).
初始化实体通过发送一个由'urn:ietf:params:xml:ns:xmpp-sasl'命名空间限定的<response/>元素来应答这个挑战; 这个元素可以包含XML字符串数据(它必须根据被初始化实体选择的SASL机制的定义来生成).
如果必要y, 接收方实体发送更多挑战而初始化实体发送更多应答.
这一系列的 挑战/应答 对 一直持续直到发生以下三件事情之一:
-
- 初始化实体退出这个验证机制的握手.
- 接收方实体报告握手失败.
- 接收方实体报告握手成功.
这些场景具体描述在接下来的章节.
放弃
初始化实体通过发送一个由'urn:ietf:params:xml:ns:xmpp-sasl'命名空间限定的<abort/>元素放弃为这个验证机制所做的握手.
I: <abort xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/>
在接收到一个<abort/>元素之后, 接收方实体必须返回一个由'urn:ietf:params:xml:ns:xmpp-sasl'命名空间限定的<failure/>元素并在其中包含一个<aborted/>子元素.
R: <failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'> <aborted/> </failure>
SASL失败
接收方实体通过发送一个由'urn:ietf:params:xml:ns:xmpp-sasl'命名空间限定的<failure/>元素来汇报这个验证机制握手失败(特定的失败原因必须放进<failure/>元素的适当子元素,如6.5定义的).
R: <failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'> <not-authorized/> </failure>
为了选择适当的SASL机制, 接收方实体应该允许一个可配置的但是合理的重试次数(至少2次但不超过5次); 这让初始化实体能(例如, 一个终端用户客户端)容忍不正确的凭证(例如, 一个输错的密码)而不要强制重新连接(如果接收方实体立刻返回SASL失败并关闭流).
如果初始化实体对同一个SASL机制尝试了合理的重试次数并且都失败了, 它可以回滚到顺序列表中的下一个机制,只要发送一个新的<auth/>请求给接收方实体, 从而开始那个机制的新的握手. 如果所有握手都失败了并且在初始化实体支持和可接受的机制列表里没有剩余的机制了, 初始化实体应该简单地关闭这个流,如4.4所述(而不是等待这个流超时).
如果初始化实体超出了重试次数, 接收方实体必须以一个流错误关闭流, 它应该是<policy-violation/>(4.9.3.14), 不过一些现有的实现发送的是<not-authorized/>(4.9.3.12).
- 实现备注: 对于 服务器-服务器 流, 如果接收方实体不能提供SASL EXTERNAL机制或其他基于TLS协商期间简历的安全上下文的SASL机制, 接收方实体可以尝试使用服务器回拨协议 XEP‑0220来完成弱身份验证; 无论如何, 如果根据本地策略弱身份验证不足够的话,那么接收方实体应该以<policy-violation/>流错误( 4.9.3.14)关闭这个流而不是等待这个流超时.
SASL成功
在确定SASL握手成功之前, 如果初始化实体在一个其保密和诚信得到TLS或同等的安全层(例如SASL GSSAPI机制)保护的初始化流头提供了一个'from'属性,那么接收方实体应该把这个验证身份结果关联到来自SASL协商的'from'地址; 如果这两个身份不匹配,那么接收方实体应该终止连接尝试(然而, 接收方实体可以有合法的理由不终止这个连接尝试, 例如, 因为它覆盖了一个连接的客户端的地址来纠正JID格式或根据终端用户的证书授予一个JID).
接收方实体通过发送一个由'urn:ietf:params:xml:ns:xmpp-sasl'命名空间限定的<success/>元素来汇报握手成功; 这个元素可以包含XML字符串数据(在SASL 属于中, 是"成功的附加数据"), 如果选择的SASL机制支持或者要求它. 如果接收方实体需要发送零长度的附加数据, 它必须传送一个单独的等号字符("=")数据.
R: <success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/>
- 提示性备注: 对于 客户端-服务器 流, 在SASL协商时通讯的授权身份是用来根据接收方服务器为初始化客户端确定的权威地址, 如 4.3.6所述.
一旦接收到<success/>元素, 初始化实体必须在现有的TCP连接上发送一个新的初始化流头到接收方实体来初始化一个新的流(如4.3.3所述, 在发送新的初始化流头之前,初始化实体不能(MUST NOT)发送一个关闭</stream>标签, 因为接收方实体和初始化实体必须确定原始的流被替换成SASL协商成功之后的流).
I: <stream:stream from='juliet@im.example.com' to='im.example.com' version='1.0' xml:lang='en' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'>
一旦从初始化实体接收到新的初始化流头, 接收方实体必须发送一个新的流头给初始化实体来应答(为此它必须生成一个新的流ID而不是重用旧的流ID).
R: <stream:stream from='im.example.com' id='gPybzaOzBmaADgxKXu9UClbprp0=' to='juliet@im.example.com' version='1.0' xml:lang='en' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'>
接收方实体也必须发送流特性, 包含任何更多的可用特性或不包含特性(通过一个空的<features/>元素).
R: <stream:features> <bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/> </stream:features>
SASL错误
SASL错误的语法如下, 那些用方括号 '[' 和 ']' 括起来的XML数据是可选的.
<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'> <defined-condition/> [<text xml:lang='langcode'> OPTIONAL descriptive text </text>] </failure>
"defined-condition" 必须是在接下来的章节里的定义的SASL相关的错误条件之一. 然而, 因为将来可能定义额外的错误条件, 如果一个实体收到一个它不理解的SASL错误条件,那么它必须把这个未知的条件视为一个通用的验证错误, 即, 等同于 <not-authorized/> (6.5.10).
内含的<text/>元素是可选的, 并且可被用于提供关于这个错误条件的应用特有的信息, 这个信息可以显示给人看但只是作为已定义的条件的补充.
因为XMPP本身定义了一个SASL应用范本并且不期望有更多专门的XMPP应用建立在SASL之上, 所以SASL错误格式不会像在XML流(4.9.4)和XML节(8.3.4)的做法一样,为应用特有的错误提供扩展性.
aborted
接收方实体确认验证握手已经被初始化实体放弃; 对<abort/>元素发送应答.
I: <abort xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/> R: <failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'> <aborted/> </failure>
account-disabled
初始化实体的帐号已经被暂时禁用; 对<auth/>元素或<response/>元素发送应答(可以包含或不包含初始化应答数据).
I: <auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='PLAIN'>AGp1bGlldAByMG0zMG15cjBtMzA=</auth> R: <failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'> <account-disabled/> <text xml:lang='en'>Call 212-555-1212 for assistance.</text> </failure>
credentials-expired
因为初始化实体提供的证书过期而验证失败; 对<response/>元素或<auth/>元素发送包含初始化应答数据的应答.
I: <response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'> [ ... ] </response> R: <failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'> <credentials-expired/> </failure>
encryption-required
初始化实体请求的机制不能使用,出非当前的流的保密性和完整性收到保护(典型的是通过TLS); 对<auth/>元素发送应答(包含或不包含初始化应答数据).
I: <auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='PLAIN'>AGp1bGlldAByMG0zMG15cjBtMzA=</auth> R: <failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'> <encryption-required/> </failure>
incorrect-encoding
初始化实体提供的数据无法被处理,因为 base 64 编码不正确(例如, 因为编码没有遵循BASE64的第四章的定义); 对<response/>元素或<auth/>元素发送包含初始化应答数据的应答.
I: <auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='DIGEST-MD5'>[ ... ]</auth> R: <failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'> <incorrect-encoding/> </failure>
invalid-authzid
初始化实体提供的authzid是非法的, 要么因为它格式不正确要么因为初始化实体没有权限授权那个ID; 对<response/>元素或<auth/>元素发送包含初始化应答数据的应答.
I: <response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'> [ ... ] </response> R: <failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'> <invalid-authzid/> </failure>
invalid-mechanism
初始化实体没有指定一个机制, 或请求的机制不被接收方实体支持; 对<auth/>元素发送应答.
I: <auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='CRAM-MD5'/> R: <failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'> <invalid-mechanism/> </failure>
malformed-request
请求是不良的(例如, <auth/>元素包含了初始化应答数据但是机制不允许这个, 或被发送的数据违反了指定的SASL机制的语法); 对<abort/>, <auth/>, <challenge/>, 或 <response/> 元素发送应答.
(下例中, <auth/>元素的XML字符串数据包含了多于255个UTF-8编码的Unicode字符,所以违反了定义于ANONYMOUS的SASL ANONYMOUS的"token"生产.)
I: <auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='ANONYMOUS'>[ ... some-long-token ... ]</auth> R: <failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'> <malformed-request/> </failure>
mechanism-too-weak
初始化实体请求的机制弱于服务器策略允许初始化实体使用的机制; 对<auth/>元素发送应答(包含或不包含初始化应答数据).
I: <auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='PLAIN'>AGp1bGlldAByMG0zMG15cjBtMzA=</auth> R: <failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'> <mechanism-too-weak/> </failure>
not-authorized
验证失败,因为初始化实体没有提供正确的证书, 或因为发生了一些普通的验证失败而接收方实体不希望泄露失败原因的特定信息; 对<response/>元素或<auth/>元素发送包含初始化应答数据的应答.
I: <response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'> [ ... ] </response> R: <failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'> <not-authorized/> </failure>
- 安全警告: 这个错误条件包含但不限于不正确的证书或不存在的用户名的情形. 为了组织目录获取攻击, 不正确的证书和不存在的用户名两者没有区别.
temporary-auth-failure
验证失败,因为接收方实体的临时性错误, 可以建议初始化实体晚点再试; 对<auth/>元素或<response/>元素发送应答.
I: <response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'> [ ... ] </response> R: <failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'> <temporary-auth-failure/> </failure>
SASL定义
SASL的范本需求里面要求使用中的协议定义必须提供以下信息.
-
服务名:
- "xmpp"
-
初始化序列:
- 在初始化实体提供一个打开的XML流头之后,接收方实体以同样的方式应答, 接收方实体提供一个可接受的验证方法的列表. 初始化实体从列表里选择一个方法并在放在<auth/>元素的'mechanism'属性的值里发送给接收方实体, 可选择包含一个初始化应答以避免多一个来回.
-
交换序列:
- 挑战和应答是通过从接收方实体发给初始化实体的<challenge/>元素和从初始化实体发送给接收方实体的<response/>元素. 接收方实体通过发送<failure/>元素来报告失败,通过发送<success/>元素来报告成功; 初始化实体通过发送<abort/>元素来放弃交换. 在成功协商之后, 双方确认原始的XML流被关闭而双方发送新的流头.
- 安全层协商:
-
授权身份的使用:
- 授权身份在XMPP中可被用于指示客户端的非缺省的<localpart@domainpart>; 空字符串等于缺少授权身份.