Jade Dungeon

XMPP登录步骤

安全保障措施

对于大多数网络应用来说,安全保障措施是必不可少的。而XMPP协议作为一个即时通讯 协议,它的安全保障主要从从以下两方面来考虑:

  • 保密性和数据完整性:不能被非法地窃听与篡改。
  • 用户身份验证。

保密性和数据完整性

XMPP协议可以选择使用安全传输层协议加强数据传输过程中的保密性和数据完整性。

安全传输协议(Transport Layer Security,简称TLS)用于在两个通信应用程序之间 提供保密性和数据完整性。\cite{plain:javaEcpDcp}该协议由TLS 记录协议(TLS Record )和TLS 握手协议(TLS Handshake)两层组成:

  • TLS记录协议位于TLS握手协议的下面,在可靠的传输协议(如TCP)上面。 TLS记录协议的一条记录包含长度字段、描述字段和 内容字段。TLS记录协议处理数据的加密,即记录协议得到要发送的消息之后,将数据 分成易于处理的数据分组,进行数据压缩处理(可选),计算数据分组的消息认证码MAC, 加密数据然后发送数据;接收到的消息首先被解密,然后校验MAC值,解压缩,重组, 最后传递给TLS握手协议。
  • TLS握手协议处理对等用户的认证,在这一层使用了公共密钥和证书,并协商 算法和加密实际数据传输的密钥,该过程在TLS记录协议之上进行。 TLS握手协议是TLS协议中最复杂的部分,它定义了10种消息,客户端和服务器 利用这10种消息相互认证,协商哈希函数和加密算法并相互提供产生加密密钥的机密 数据。TLS记录协议会在加密算法中用到这些加密密钥,从而提供数据保密性和一致性 保护。

用户身份验证

在用户身份认证方面,XMPP协议通过SASL机制来检查用户认证。

SASL(Simple Authentication and Security Layer)是一种用来扩充C/S模式验证能力的 机制。在Postfix可以利用SASL来判断用户是否有权使用转发服务,或是辨认谁在使用你的 服务器。

XMPP使用TLS和SASL登录

图\ref{fig:ch03.xmpp.connect.png}对XMPP协议建立连接与验证的过程给出了一个直观的描述:

登录过程

接来下详细看一下XMPP的登录过程:

步骤1:建立TLS连接

为了使用TLS建立安全的连接,首先要确认服务器与客户端两都实现了对TLS的支持。

在XMPP协议中任何与服务器的沟通都要建立Stream,登录验证过程也不例外。在服务器 返回的Stream标签的第一个子元素就是<stream:features>元素,里面包含了当前服务器 所支持和特性。如果服务器支持TLS的话,在features里会包含<starttls>元素。例如:

<stream:features>
	<starttls xmlns="urn:ietf:params:xml:ns: xmpp-tls"></starttls>
	...
</stream:features>

因为服务器响应中的<starttls>元素表示支持TLS协议。这样如果客户端也实现了对TLS 的支持的话,那么就具备了建立TLS连接前提条件。如果客户端也支持TLS协议的话就可以 通过发出<starttls>申请使用TLS连接:

<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>

服务器发回响应<proceed>给客户端表示同意建立TLS连接的申请:

<proceed xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>

这时客户端就可以重新建立一个基于TLS的安全连接。

步骤2:验证用户身份

由于之前已经重新建立了一个基于TLS的新连接,所以客户端发出一个<stream:stream> 元素打开一个新的XMPP连接流,而服务器响应的features里所包含的mechanisms元素 列出了服务器所支持的SASL实现机制\cite{plain:xmppJsJq}:

<stream:features>
	<mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl">
		<mechanism>PLAIN</mechanism>
		<mechanism>DIGEST-MD5</mechanism>
		<mechanism>ANONYMOUS</mechanism>
	</mechanisms>
</stream:features>

常见的实现机制包括有:

  • DIGEST-MD5:如果帐号和密码都在Client对象中提供了,这种机制是首选,即使没有 TLS加密也是安全的。
  • PLAIN:如果DIGEST-MD5无效,就使用此种机制。在没有TLS加密时是不安全的。
  • ANONYMOUS:此种机制在没有提供帐号和密码时使用。服务器将随机产生临时帐号和 资源,提供限制的有效服务。

通过服务器给出mechanisms列表,客户端可以选择一个自己和服务器都支持机制,比如 选择最常见的DIGEST-MD5

<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' 
	mechanism='DIGEST-MD5'/>

确定了验证机制以后,就进入到验证阶段。服务器发送一个<challenge>元素给客户端, 内容采用BASE64编码。例如:

<challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>
	cmVhbG09InNvbWVyZWFsbSIsbm9uY2U9Ik9BNk1HOXRFUU
	dtMmhoIixxb3A9ImF1dGgiLGNoYXJzZXQ9dXRmLTgsYWxn
	b3JpdGhtPW1kNS1zZXNzCg==
</challenge>

客户端返回<response>元素给服务器,内容也是用BASE64编码:

<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>
	dXNlcm5hbWU9InNvbWVub2RlIixyZWFsbT0ic29tZXJlYWx
	tIixub25jZT0iT0E2TUc5dEVRR20yaGgiLGNub25jZT0iT0
	E2TUhYaDZWcVRyUmsiLG5jPTAwMDAwMDAxLHFvcD1hdXRoL
	GRpZ2VzdC11cmk9InhtcHAvZXhhbXBsZS5jb20iLHJlc3Bv
	bnNlPWQzODhkYWQ5MGQ0YmJkNzYwYTE1MjMyMWYyMTQzYWY
	3LGNoYXJzZXQ9dXRmLTgK
</response>

如果客户端给出的响应正确则服务器会返回<success>通知客户端登录成功:

<success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/>

步骤3:绑定JID与会话

登录成功以后还是需要建立一个新的Stream。服务器响应中的两人个元素bindsession分别表示需要绑定当前连接的Resource和建立会话:

<stream:features>
  <bind xmlns="urn:ietf:params:xml:ns:xmpp-bind">
    <required />
  </bind>
  <session xmlns="urn:ietf:params:xml:ns:xmpp-session">
    <optional />
  </session>
</stream:features>

客户端发出<iq>元素通知服务器当前连接的Resource名称,<session>表示开始会话:

<iq id="ywXR5-0" type="set">
	<bind xmlns="urn:ietf:params:xml:ns:xmpp-bind">
		<resource>mob</resource>
	</bind>
</iq>

<iq id="ywXR5-1" type="set">
	<session xmlns="urn:ietf:params:xml:ns:xmpp-session"/>
</iq>

到此,整个登录过程已经完成。