openfire SASL的使用与SASL协商

SASL定义

SASL的范本需求里面要求使用中的协议定义必须提供以下信息.

服务名:
"xmpp"
初始化序列:
在初始化实体提供一个打开的XML流头之后,接收方实体以同样的方式应答, 接收方实体提供一个可接受的验证方法的列表. 初始化实体从列表里选择一个方法并在放在<auth/>元素的'mechanism'属性的值里发送给接收方实体, 可选择包含一个初始化应答以避免多一个来回.
交换序列:
挑战和应答是通过从接收方实体发给初始化实体的<challenge/>元素和从初始化实体发送给接收方实体的<response/>元素. 接收方实体通过发送<failure/>元素来报告失败,通过发送<success/>元素来报告成功; 初始化实体通过发送<abort/>元素来放弃交换. 在成功协商之后, 双方确认原始的XML流被关闭而双方发送新的流头.
安全层协商:
安全层,对于接收方实体来说,发送完<success/>元素的'>'字符之后立刻生效, 对于初始化实体来说,在接收到<success/>元素的'>'字符之后立刻生效. 层的顺序是先  TCP, then  TLS, then  SASL, 然后 XMPP.
授权身份的使用:

    授权身份在XMPP中可被用于指示客户端的非缺省的<localpart@domainpart>; 空字符串等于缺少授权身份.


SASL 的使用

概览

XMPP 有一个验证流的方法,即XMPP特定的SASL(简单验证和安全层)[SASL]。SASL提供了一个通用的方法为基于连接的协议增加验证支持,而XMPP使用了一个普通的XML名字空间来满足SASL的需要。
以下规则应用于:
  1. 如果SASL协商发生在两台服务器之间,除非服务器宣称的DNS主机名得到解析,否则不能(MUST NOT)进行通信。(参见 服务器间的通信,如下:).

    服务器-服务器通信

    一个兼容的服务器实现必须(MUST)支持TLS和SASL,用于域间的通信.因为历史原因,一个兼容的实施也应该(SHOULD)支持服务器回拨(第八章).
    因为服务提供者是一个策略问题,对于任何给定域和其他域的通信中,它是可选的(OPTIONAL),服务器之间的通信可以(MAY)被任何特定部署的管理员禁止。如果一个特殊的域允许域间的通信,它应该(SHOULD)允许高安全性。
    管理员可能想在服务器间使用SASL来通信,以确保双方的验证和保密性(比如在机构的私有网络).兼容实施应该(SHOULD)为这个目的支持SASL.
    服务器宣称的DNS主机名被解析之前,服务器-服务器通信不能(MUST NOT)继续进行。应该首先尝试解析[SRV]记录,其服务名为"xmpp-server",协议名为"tcp",整个资源记录类似"_xmpp-server._tcp.example.com."(使用字符"xmpp-server"表示服务ID是经过IANA注册的,注意要用"xmpp-server"取代以前用的"jabber",因为以前的用法不符合[SRV]标准;希望保持向后兼容的实现可以继续查找或应答"jabber"服务ID).如果SRV查找失败,退而求其次,将查找一个正规的IPv4/IPv6地址记录来决定IP地址,使用"xmpp-server"端口5269,这个端口是在IANA注册了的。
    服务器回拨防止域欺骗,从而使得伪造XML节更为困难.它和SASL和TLS不一样,它不是一个用于验证、安全或加密服务器之间的流的机制, 所以只是服务器身份的微弱确认而已。而且除非它使用了DNSSec [DNSSEC]否则它 容易受到DNS中毒攻击,即使DNS信息是正确的,如果攻击者劫持了远程域,回拨也不能防止它的攻击.需要健壮的安全性的域应该(SHOULD)使用TLS和SASL.如果服务器间的验证使用了SASL,回拨就不应该(SHOULD NOT)使用了,因为它是多余的.
  2. 如果初始化实体有能力使用 SASL 协商, 它必须(MUST)在初始化流的头信息中包含一个值为"1.0"的属性'version'。
  3. 如果接收实体有能力使用 SASL 协商, 它必须(MUST)在应答从初始化实体收到的打开流标签时(如果打开的流标签包含一个值为"1.0"的'version'属性),通过'urn:ietf:params:xml:ns:xmpp-sasl'名字空间中的<mechanisms/>元素声明一个或多个验证机制.
  4. 当 SASL 协商时, 一个实体不能(MUST NOT)在流的根元素中发送任何空格符号(匹配 production [3] content of [XML])作为元素之间的分隔符(在以下的SASL例子中任何空格符号的出现仅仅是为了增加可读性); 这条禁令帮助确保安全层字节的精确度。
  5. 当SASL握手时,在XML元素中使用的任何 XML 字符数据必须被编码成 base64, 编码遵循 RFC 3548 第三章的规定。
  6. 如果一个 简单名字"simple username" 规范被选定的SASL机制所支持,(比如, 这被 DIGEST-MD5 和 CRAM-MD5 机制支持但不被 EXTERNAL 和 GSSAPI 机制支持), 验证的时候初始化实体应该(SHOULD)在服务器间通信时提供 简单名字 自身的发送域(IP地址或包含在一个域标识符中的域名全称),在客户端与服务器之间通信时提供注册用户名(包含在一个XMPP节点标识符中的用户或节点名)。
  7. 如果初始化实体希望以另一个实体的身份出现并且SASL机制支持授权ID的传输,初始化实体在SASL握手时必须(MUST)提供一个授权ID。如果初始化实体不希望以另一个实体的身份出现,初始化实体在SASL握手时不能(MUST NOT)提供一个授权ID。在 [SASL] 的定义中,除非授权ID不同于从验证ID(详见[SASL])中得到的缺省的授权ID,初始化实体不能(MUST NOT)提供授权ID。如果提供了,这个授权ID的值必须(MUST)是<domain>的格式(对于服务器来说)或<node@domain>的格式(对于客户端来说).
  8. 在成功进行包括安全层的SASL握手之后,接收实体必须(MUST)丢弃任何从初始化实体得到的而不是从SASL协商本身获得的信息。
  9. 在成功进行包括安全层的SASL握手之后,初始化实体必须(MUST)丢弃任何从接收实体得到的而不是从SASL协商本身获得的信息。
  10. 参看 强制执行的技术 (如下:) ,了解关于必须(MUST)支持的机制.

    强制实现的技术

    最低要求, 所有实现必须(MUST)支持以下机制:
    对于验证: SASL [DIGEST-MD5] 机制
    对于机密性: TLS (使用 TLS_RSA_WITH_3DES_EDE_CBC_SHA 密码)
    对于两者: TLS 加 SASL EXTERNAL(使用 TLS_RSA_WITH_3DES_EDE_CBC_SHA 密码支持客户端证书)

叙述

一个初始化实体使用SASL和接收实体做验证的步骤如下:
  1. 初始化实体请求SASL验证,它发送一个打开的XML流头信息给接收实体,其'version'属性的值为"1.0".
  2. 在发送一个XML流头回复之后,接收实体声明一个可用的SASL验证机制清单;每个机制作为一个<mechanism/>元素,作为子元素包含在<mechanisms/>容器元素(其名字空间为'urn:ietf:params:xml:ns:xmpp-sasl')中,而<mechanisms/>则包含在流名字空间中的<features/>元素中。如果在使用任何验证机制之前需要使用TLS(见第五章),接收实体不能(MUST NOT)在TLS握手之前提供可用的SASL验证机制清单。如果初始化实体在优先的TLS协商过程中呈现了一个合法的证书,接收实体应该(SHOULD)在SASL握手中提出一个SASL外部机制给初始化实体,尽管这个外部机制可以(MAY)在其它环境下提供。
  3. 初始化实体发送一个符合'urn:ietf:params:xml:ns:xmpp-sasl'名字空间的<auth/>元素(其中包含了适当的'mechanism'属性值)给接收实体,以选择一个机制。如果这个机制支持或需要,这个元素可以(MAY)包含XML字符数据(在SASL术语中,即“初始化应答”);如果初始化实体需要发送一个零字节的初始化应答,它必须(MUST)传输一个单独的等号作为应答,这表示应答有效但不包含数据。
  4. 如果必要,接收实体向初始化实体发送一个符合'urn:ietf:params:xml:ns:xmpp-sasl'名字空间的<challenge/>元素来发出挑战;这个元素可以(MAY)包含XML字符数据(必须按照初始化实体选择的SASL机制进行一致性运算)。
  5. 初始化实体向接收实体发送符合'urn:ietf:params:xml:ns:xmpp-sasl'名字空间的<response/>元素作为应答;这个元素可以(MAY)包含XML字符数据(必须按照初始化实体选择的SASL机制进行一致性运算)。
  6. 如果必要,接收实体发送更多的挑战给初始化实体,初始化实体发送更多的回应。
这一系列的 挑战/应答 组,持续进行直到发生以下三件事中的一件为止:
  1. 初始化实体向接收实体发送符合'urn:ietf:params:xml:ns:xmpp-sasl'名字空间的<abort/>元素以中止握手。在接收到<abort/>元素之后,接收实体应该(SHOULD)允许一个可配置的但是合理的重试次数(至少2次),然后它必须(MUST)终止TCP连接;这使得初始化实体(如一个最终用户客户端)能够容忍可能不正确的credentials(如密码输入错误)而不用强制重新连接。
  2. 接收实体向初始化实体发送符合'urn:ietf:params:xml:ns:xmpp-sasl'名字空间的<failure/>元素以报告握手失败(详细的失败原因应该在<failure/>的一个适当的子元素中沟通,在第六章第四节中的SASL Errors中定义)。如果失败的情况发生了,接收实体应该(SHOULD)允许一个可配置的但是合理的重试次数(至少2次), 然后它必须(MUST)终止TCP连接;这使得初始化实体(如一个最终用户客户端)能够容忍可能不正确的credentials(如密码输入错误)而不用强制重新连接。
  3. 接收实体向初始化实体发送符合'urn:ietf:params:xml:ns:xmpp-sasl'名字空间的<success/>元素以报告握手成功;如果所选择的SASL机制要求,这个元素可以(MAY)包含XML字符数据(见SASL术语,“成功的额外数据”)。接收到<success/> 元素之后,初始化实体必须(MUST)发送一个打开的XML流头信息给接收实体以发起一个新的的流(不需要先发送一个 </stream>标签,因为在发送和接收到<success/>元素之后,接收实体和初始化实体必须确认原来的流被关闭了)。从初始化实体接收到新的流头信息之后,接收实体必须(MUST)发送一个新的流头信息给初始化实体作为回应,附上任何可用的特性(但不包括 STARTTLS 和 SASL 特性)或一个空的 <features/> 元素(这表示没有更多的特性可用);任何没有在本文定义的附加特性必须(MUST)在XMPP的相关扩展中定义。

SASL 定义

[SASL]的必要条件要求通过协议定义来提供以下信息:
service name(服务名): "xmpp"
initiation sequence(开始序列): 当初始化实体提供一个打开的XML流头信息并且接收实体善意回应之后,接收实体提供一个可接受的验证方法清单。初始化实体从这个清单中选择一个方法,把它作为 <auth/> 元素的 'mechanism' 属性的值发送给接收实体,也可以选择发送一个初始化应答以避免循环。
exchange sequence(交换序列): 挑战和回应的交换,从接收实体发送给初始化实体的 <challenge/> 元素和从初始化实体发送给接收实体的 <response/> 元素信息。接收实体通过发送 <failure/>元素报告失败,发送<success/>元素报告成功;初始化实体通过发送<abort/> 元素中止交换。成功的协商之后,两边都认为原来的XML流已经关闭并且都开始发送新的流头信息。
security layer negotiation(安全层协商): 安全层在接收实体发送 <success/> 元素的关闭字符">"之后立刻生效,在初始化实体发送 <success/> 元素的关闭字符">"之后也立刻生效。层的顺序是 [TCP],[TLS],然后是 [SASL],然后是 [XMPP]。
use of the authorization identity(授权ID的使用): 授权ID可在xmpp中用于表示一个客户端的非缺省的<node@domain>,或一个服务器的<domain> 。

SASL 错误

SASL相关的错误条件定义如下:
  • <aborted/> -- 接收实体认可由初始化实体发送的<abort/>元素;在回应一个<abort/>元素时发送。
  • <incorrect-encoding/> -- 由初始化实体提供的数据无法处理,因为[BASE64]编码不正确(例如,因为编码不符合[BASE64]的第三章); 在回应一个包含初始化响应数据的<response/> 元素或<auth/>元素时发送.
  • <invalid-authzid/> -- 由初始化实体提供的授权id是非法的,因为它的格式不正确或初始化实体无权给那个ID授权;在回应一个包含初始化响应数据的<response/> 元素或<auth/>元素时发送。
  • <invalid-mechanism/> -- 初始化实体不能提供一个机制活、或请求一个不被接受实体支持的机制;在回应一个<auth/>元素时发送。
  • <mechanism-too-weak/> -- 初始化实体请求的机制比服务器策略对它的要求弱;在回应一个包含初始化响应数据的<response/> 元素或<auth/>元素时发送。
  • <not-authorized/> -- 验证失败,因为初始化实体没有提供合法的credentials(这包括但不限于未知用户名等情形);在回应一个包含初始化响应数据的<response/> 元素或<auth/>元素时发送。
  • <temporary-auth-failure/> -- 验证失败,因为接收实体出现了临时的错误;在回应一个<response/> 元素或<auth/>元素时发送。

客户端-服务器 示例

以下例子展示了一个客户端和一个服务器使用SASL作验证的数据流,通常是在成功的TLS握手之后(注意:以下显示的替代步骤仅用于举例说明协议的失败情形;它们不够详尽也不需要由例子中的数据传送来触发)。
步骤 1: 客户端初始化流给服务器:
   <stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'>
步骤 2: 服务器向客户端发送流标签作为应答:
   <stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' id='c2s_234' from='example.com' version='1.0'>
步骤 3: 服务器通知客户端可用的验证机制:
   <stream:features>
     <mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>
       <mechanism>DIGEST-MD5</mechanism>
       <mechanism>PLAIN</mechanism>
     </mechanisms>
   </stream:features>
步骤 4: 客户端选择一个验证机制:
   <auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='DIGEST-MD5'/>
步骤 5: 服务器发送一个 [BASE64] 编码的挑战给客户端:
   <challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>
   cmVhbG09InNvbWVyZWFsbSIsbm9uY2U9Ik9BNk1HOXRFUUdtMmhoIixxb3A9ImF1dGgi
   LGNoYXJzZXQ9dXRmLTgsYWxnb3JpdGhtPW1kNS1zZXNzCg==
   </challenge>
解码后的挑战信息是:
   realm="somerealm",nonce="OA6MG9tEQGm2hh",\
   qop="auth",charset=utf-8,algorithm=md5-sess
步骤 5 (替代): 服务器返回一个错误给客户端:
   <failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>
     <incorrect-encoding/>
   </failure>
   </stream:stream>
步骤 6: 客户端发送一个[BASE64]编码的回应这个挑战:
   <response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>
   dXNlcm5hbWU9InNvbWVub2RlIixyZWFsbT0ic29tZXJlYWxtIixub25jZT0i
   T0E2TUc5dEVRR20yaGgiLGNub25jZT0iT0E2TUhYaDZWcVRyUmsiLG5jPTAw
   MDAwMDAxLHFvcD1hdXRoLGRpZ2VzdC11cmk9InhtcHAvZXhhbXBsZS5jb20i
   LHJlc3BvbnNlPWQzODhkYWQ5MGQ0YmJkNzYwYTE1MjMyMWYyMTQzYWY3LGNo
   YXJzZXQ9dXRmLTgK
   </response>
解码后的回应信息是:
   username="somenode",realm="somerealm",\
   nonce="OA6MG9tEQGm2hh",cnonce="OA6MHXh6VqTrRk",\
   nc=00000001,qop=auth,digest-uri="xmpp/example.com",\
   response=d388dad90d4bbd760a152321f2143af7,charset=utf-8
步骤 7: 服务器发送另一个[BASE64]编码的挑战给客户端:
   <challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>
   cnNwYXV0aD1lYTQwZjYwMzM1YzQyN2I1NTI3Yjg0ZGJhYmNkZmZmZAo=
   </challenge>
解码后的挑战信息是:
   rspauth=ea40f60335c427b5527b84dbabcdfffd
步骤 7 (或者): 服务器返回一个错误给客户端:
   <failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>
     <temporary-auth-failure/>
   </failure>
   </stream:stream>
步骤 8: 客户端应答这个挑战:
   <response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/>
步骤 9: 服务器通知客户端验证成功:
   <success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/>
步骤 9 (或者): 服务器通知客户端验证失败:
   <failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>
     <temporary-auth-failure/>
   </failure>
   </stream:stream>
步骤 10: 客户端发起一个新的流给服务器:
   <stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'>
步骤 11: 服务器发送一个流头信息回应客户端,并附上任何可用的特性(或空的features元素):
   <stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' id='c2s_345' from='example.com' version='1.0'>
   <stream:features>
     <bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/>
     <session xmlns='urn:ietf:params:xml:ns:xmpp-session'/>
   </stream:features>

服务器-服务器 示例

以下例子展示了一个服务器和另一个服务器使用SASL作验证的数据流,通常是在成功的TLS握手之后(注意:以下显示的替代步骤仅用于举例说明协议的失败情形;它们不够详尽也不需要由例子中的数据传送来触发)。
步骤 1: 服务器1 发起一个流给 服务器2 :
   <stream:stream xmlns='jabber:server' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'>
步骤 2: 服务器2 回应一个流标签给 服务器1:
   <stream:stream xmlns='jabber:server' xmlns:stream='http://etherx.jabber.org/streams' from='example.com' id='s2s_234' version='1.0'>
步骤 3: 服务器2 通知 服务器1 可用的验证机制:
   <stream:features>
     <mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>
       <mechanism>DIGEST-MD5</mechanism>
       <mechanism>KERBEROS_V4</mechanism>
     </mechanisms>
   </stream:features>
步骤 4: 服务器1 选择一个验证机制:
   <auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='DIGEST-MD5'/>
步骤 5: 服务器2 发送一个[BASE64]编码的挑战给 服务器1:
   <challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>
   cmVhbG09InNvbWVyZWFsbSIsbm9uY2U9Ik9BNk1HOXRFUUdtMmhoIixxb3A9
   ImF1dGgiLGNoYXJzZXQ9dXRmLTgsYWxnb3JpdGhtPW1kNS1zZXNz
   </challenge>
解码后的挑战信息是:
   realm="somerealm",nonce="OA6MG9tEQGm2hh",\
   qop="auth",charset=utf-8,algorithm=md5-sess
步骤 5 (替代): 服务器2 返回一个错误给 服务器1:
   <failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>
     <incorrect-encoding/>
   </failure>
   </stream:stream>
步骤 6: 服务器1 发送一个[BASE64]编码的回应这个挑战:
   <response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>
   dXNlcm5hbWU9ImV4YW1wbGUub3JnIixyZWFsbT0ic29tZXJlYWxtIixub25j
   ZT0iT0E2TUc5dEVRR20yaGgiLGNub25jZT0iT0E2TUhYaDZWcVRyUmsiLG5j
   PTAwMDAwMDAxLHFvcD1hdXRoLGRpZ2VzdC11cmk9InhtcHAvZXhhbXBsZS5v
   cmciLHJlc3BvbnNlPWQzODhkYWQ5MGQ0YmJkNzYwYTE1MjMyMWYyMTQzYWY3
   LGNoYXJzZXQ9dXRmLTgK
   </response>
解码后的应答信息是:
   username="example.org",realm="somerealm",\
   nonce="OA6MG9tEQGm2hh",cnonce="OA6MHXh6VqTrRk",\
   nc=00000001,qop=auth,digest-uri="xmpp/example.org",\
   response=d388dad90d4bbd760a152321f2143af7,charset=utf-8
步骤 7: 服务器2 发送另外一个[BASE64]编码的挑战给 服务器1:
   <challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>
   cnNwYXV0aD1lYTQwZjYwMzM1YzQyN2I1NTI3Yjg0ZGJhYmNkZmZmZAo=
   </challenge>
解码后的挑战信息是:
   rspauth=ea40f60335c427b5527b84dbabcdfffd
步骤 7 (或者): 服务器2 返回一个错误给 服务器1:
   <failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>
     <invalid-authzid/>
   </failure>
   </stream:stream>
步骤 8: 服务器1 回应挑战:
   <response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/>
步骤 8 (或者): 服务器1 中止协商:
   <abort xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/>
步骤 9: 服务器2 通知 服务器1 验证成功:
   <success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/>
步骤 9 (或者): 服务器2 通知 服务器1 验证失败:
   <failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>
     <aborted/>
   </failure>
   </stream:stream>
步骤 10: 服务器1 重新发起一个新的流给 服务器2:
   <stream:stream xmlns='jabber:server' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'>
步骤 11: 服务器2 发送一个流头信息应答 服务器1 ,并附上任何可用的特性(或一个空的features元素).:
   <stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' from='example.com' id='s2s_345' version='1.0'>
   <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 机制,:

  1. 当初始化实体在TLS协商中出示了一个证书,这个证书被接收方实体接受了,接收方根据本地服务策略把它用于强身份验证(例如, 因为证书没有过期,没有撤销,并且被锚定到一个接收方实体信任的root账户).
  2. 接收方实体期望初始化实体能够验证和授权这个证书所提供的身份; 在服务器-服务器流的情形下, 接收方实体可能有这样一个预期,因为初始化实体的证书所展示的DNS域名和初始化流头中相应的'from'属性是匹配的, 这里使用TLS‑CERTS的匹配规则; 在客户端-服务器流的情形下, 接收方实体可能有这样一个预期,是因为在初始化实体的证书中展示的纯JID和在这个服务器上注册的一个用户帐号匹配,或者因为其他包含在初始化实体证书中的信息和被允许使用该服务器访问XMPP网络的某个实体相匹配.

无论如何, 接收方实体在其他情况下也一样可以提供 SASL EXTERNAL 机制.

当接收方实体提供 SASL EXTERNAL 机制, 接收方实体应该首先列出它提供的SASL机制的 EXTERNAL 机制列表,而初始化实体应该尝试首先使用EXTERNAL机制来进行SASL协商(这个选择往往会增加双方相互进行证书验证的可能性).

13.8定义了必须支持的SASL机制; 自然的, 也一样可以支持其他的SASL机制.

提示性备注: 在XMPP的上下文中使用SASL的最佳实践,使用ANONYMOUS机制请参考 XEP‑0175,使用EXTERNAL机制请参考 XEP‑0178.
数据格式

以下数据格式规则适用于SASL协商:

  1. 当SASL协商时, 实体不能(MUST NOT)在XML元素之间发送任何空格符号(即, 从初始化实体发送的'urn:ietf:params:xml:ns:xmpp-sasl'命名空间限定的<auth/>顶级元素的最后一个字符, 到接收方实体发送的'urn:ietf:params:xml:ns:xmpp-sasl'命名空间限定的<success/>顶级元素的最后一个字符). 这个禁令帮助确保正确的安全层字节精确度. 本文中任何在SASL例子中出现的这类空格只是为了增加可读性.
  2. 任何包含在XML元素中的XML字符串数据必须使用base 64编码, 这里的编码要坚持BASE64第四章的定义,并且填充位设为零.
  3. 作为附录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机制的回合:

  1. 当SASL客户端(XMPP "初始化实体") 请求一个验证交换时, 如果使用了适当的SASL机制,它可以在它的请求中包含 "初始化应答" 数据. 在XMPP中, 要实现这一点,就把初始化应答作为XML字符串数据包含在<auth/>元素中.
  2. 在验证交换的结尾, 如果使用了适当的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>
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值