这个文档定义了http层与xmpp之间的通讯联络。(这里是原文档。)
NOTICE:这个协议是Jabber Softeware Foundation(JSF)的一个草案,在它成为正式的标准前可能会有一些其他的变化。
协议信息
状态:Draft
类型:Standards Track
编号:0124
版本:1.5
最后更新:2006-04-28
依赖:XMPP Core, RFC 1945, RFC 2068, RFC 3174
XMPP相关
XMPP协议是由JSF的XMPP Core (RFC 3920)和XMPP IM (RFC 3921)规范定义的一种标准方法。本文档定义的协议不属于XMPP协议本身,它仅为XMPP协议的一种扩展,而不是对XMPP的升级,修正。
一致的约定
对于以下的一些关键字的解释已经在RFC 2119中有过描述,本文档遵循这种描述。关键字:"MUST", "SHALL", "REQUIRED"; "MUST NOT", "SHALL NOT"; "SHOULD", "RECOMMENDED"; "SHOULD NOT", "NOT RECOMMENDED"; "MAY", "OPTIONAL"。(翻译中不改变,翻译这些关键字)
内容目录
1.介绍
1,介绍
XMPP Core定义了绑定到TCP的XML流,作为Jabber/XMPP联络的传输层。然而XMPP-TCP的绑定不总是行的通的。这个文档描述通过部署一个服务端的连接管理器(通过HTTP与客户端联络,而不是TCP)来使用HTTP为传输的绑定。
在作者发布这个文档之前,已经有其他的方法解决。一个可行的方法是通过HTTP Cookies使用HTTP传输中的一系列状态。然而有很多其他的系统仅支持HTTP请求和响应,更糟糕的是一些系统隐藏或者移出了cookies相关的头,这样cookies方法就不适用了。
另一个可行的方法是修改或者扩展Jabber HTTP Polling(xep-0025)。不幸的是它也依靠cookies,不符合下面要描述的大多数要求,并且在不破坏当前实现的情况下不能扩展。
由此,本文档定义了一种通过HTTP与XMPP服务器传输的新方法。所有信息都被编码在HTTP请求和响应内容中。每个HTTP内容包含一个<body/>XML元素,它可以带有0个或者多个XML节。
虽然本规范列出了一些XMPP的特性,不过绑定并不是XMPP的一部分。实际上,该协议是可扩展的,被用来实现任意双向的XML节。
2,术语
2.1 HTTP术语
参考在RFC 1945,RFC 2068定义的HTTP
3,必要条件
平台、安全以及其他的局限性使得很多客户端只能通过HTTP连接网络资源。下面的设计需求考虑了尽可能的像标准的TCP连接一样的工作。
与有局限的运行环境的兼容。
与有局限的网络连接的兼容。
故障的恢复。
可扩展性。
更少的带宽消耗。
更多的响应。
支持polling
客户端发送的XML节有序的进入服务端。
防止恶意地HTTP请求被发送到session
与有局限的运行环境的兼容性意味着受到下面的限制:
客户端不需要存取每个HTTP请求和响应的头。
每个HTTP请求和响应的内容应该是一个单根的可被分析的XML。
客户端应该指定他们要收到的HTTP响应的Content-Type。
4,采用的结构
XMPP-HTTP绑定采用的结构与RFC 3920中定义的XMPP-TCP绑定的结构不同。由于HTTP与XMPP之间不是本地绑定,因此我们设想大多数的XMPP实现将使用一种特殊的“连接管理器”去处理HTTP连接,而不是通常的TCP连接。实际上,这个连接管理器是个特别的HTTP服务,它承担着HTTP请求、响应、XMPP服务实现的XML流(或者是API)之间的信息传输,以促使HTTP客户端连接到XMPP服务端。我们可以通过下图解释这种结构:
XMPP Server
|
| [XML流/API]
|
Connection Manager
|
| [HTTP + <body/>内容]
|
HTTP Client
这篇文档仅针对HTTP客户端与连接管理器之间的联络进行规定。它并没有针对连接管理器与XMPP服务端的联络,因为这种联络已有特定的实现了。
再者,HTTP绑定中没有哪方面可以限制其使用client-to-server联络。本文档仅关注于不能固有TCP连接和不能采用RFC 3920定义的TCP绑定的客户端。
5,HTTP Version和HTTP Headers
客户端SHOULD在HTTP/1.1连接上发送请求。然而,一个受约束的客户端MAY打开一个新的HTTP/1.0连接发送请求。
请求和响应MAY包含HTTP headers,接收者SHOULD忽略任何头信息。
6,压缩
客户端MAY在请求中包含HTTP Accept-Encoding头。如果连接管理器收到这样的请求,它MAY在响应中包含HTTP Content-Encoding头(与请求相对应的一种编码方式),并且压缩相应的响应内容。
TLS压缩和流压缩是NOT RECOMMENDED的,因为压缩是在HTTP层协商的。TLS压缩和流压缩SHOULD NOT同时用在内容编码中。
7,<body/>元素内容
每个HTTP request和response都包含单一的<body/>元素内容,这个<body/>MUST(必须)包含0个或者是多个完整的XML元素,而MUST NOT(不能)包含部分的XML内容。
如果<body/>的内容不为空,那么它必须(MUST)包含以下内容之一:
一个或者多个XMPP节(stanza,以后都译为“节”),比如:<message/>, <presence/>, 和/或 <iq/>
一个完整的<stream:features/>元素。这种情况下该元素体内容必须(MUST)有命名空间-xmlns:stream='http://etherx.jabber.org/streams'。
一个完整的被用来SASL协商,以及为'urn:ietf:params:xml:ns:xmpp-sasl'命名空间许可的元素。
与错误情形有关的各种xml元素。更多信息请参考下面的 Binding Conditions。
Note:包含TLS协商的元素是被允许的,但它是不推荐的(NOT RECOMMENDED)。参考下面的其他准备工作。
<body/>元素内容SHOULD被'http://jabber.org/protocol/httpbind'命名空间许可,它的子元素SHOULD被其各自的命名空间许可(比如,针对stream 每个客户端请求的<body/>元素MUST通过'rid'属性,以持有一系列连续的请求标识号。详细信息参考本文档的Request IDs章节。
8,开始一个HTTP Session(这里的Session与web开发中的Session对象有所不同,它是指即时通讯阶段的信息载体)
8.1 请求一个Session
在客户端第一次向连接管理器发送请求的时候建立新的session。
第一次请求时,<body/>元素SHOULD具有下面列出的属性(这些属性SHOULD NOT被包含在其他任何请求中,除了Adding Streams To A Session章节中指定的以外)。
to - 这个属性指定了目标域(domain)。
xml:lang - 这个属性(在Section 2.12 of XML 1.0中定义)指定了在session存在期间,发送或接收的xml字符信息的语言。
wait - 这个属性指定了在session响应任意请求之前,连接管理器所能够等待的最长时间(以秒为单位)。这就使得客户端可以防止TCP连接由于在休止期(inactivity)就终止。
hold - 这个属性指定了在session中,连接管理器允许一次保持等待的最大请求数。(例如,如果一个受限制的客户端不能够同时对同一个HTTP服务器打开超过2个连接,那么SHOULD指定为1)。
一些客户端被限制只能接受指定了Content-Types(比如'text/html')的HTTP响应,那么第一次请求时的<body/>元素MAY拥有'content'属性,这要求HTTP Content-Type头MUST在这个session周期内所有的连接管理器响应中出现,如果客户端请求不包含'content'属性,那么响应的HTTP Content-TypeMUST是'text/xml; charset=utf-8'。
Note:客户端请求的HTTP Content-Type也SHOULD是'text/xml; charset=utf-8',如果客户端被限制这么做,那么它MAY指定其他的值(比如'application/x-www-form-urlencoded'或者'text/plain')。客户端和连接管理器SHOULD忽略所有接收到的HTTP Content-Type头。
Example 1. 请求一个HTTP Session
POST /webclient HTTP/1.1
charset=utf-8
Content-Length: 104
<body content='text/xml; charset=utf-8'
hold='1'
rid='1573741820'
to='jabber.org'
route='xmpp:jabber.org:9999'
secure='true'
wait='60'
xml:lang='en'
xmlns='http://jabber.org/protocol/httpbind'/>
Note:与XEP-0025定义的协议不同,一个打开的<stream:stream>标记没有被发送。在这里定义的协议只是来自连接管理器与客户端之间的XML流。任何在连接管理器与XMPP服务之间的XML流都是连接管理器的职责。
Note:在第一次请求之后的请求MUST包含一个有效的'sid'属性(值由连接管理器在session创建成功后的响应中提供)。初始化请求(第一个)是唯一一个MUST NOT带有'sid'属性的<body>元素。
8.2 创建Session
在接收到一个创建新的session请求之后,连接管理器MUST生成一个不透明的、不可预知的、唯一的session标识(SID),它由响应的<body/>元素返回给客户端。
连接管理器MUST指定一个'wait'属性,它指定了允许连接管理器在响应请求之前等待的最长时间(以秒为单位)。这个时间值MUST小于或者等于session请求中指定的时间。
连接管理器MAY指定'request'属性来限制客户端并发的请求数量,RECOMMENDED的值是2。对于仅支持polling形式(NOT RECOMMENDED)的服务器,MUST设置'request'属性为1,以防止并发的请求。无论如何,客户端MUST NOT发出的并发请求数超过连接管理器指定的数目。
在创建session的响应中,连接管理器SHOULD包含2个额外的属性,分别指定最短的连接间隔和最长的不活跃期(都以秒为单位)。这些参数指导客户端进行恰当的行为(比如:不能过分的发送空请求;没有任何请求的时间段不能过长)。
在创建session的响应中,连接管理器MAY包含'accept'属性指定压缩内容。在收到session响应的'accept'属性后,客户端MAY在以后的请求中包含一个HTTP Content-Encoding头以及相应地压缩请求内容。
对于请求和响应,<body>元素及其内容都SHOULD是UTF-8编码。如果请求/响应地HTTP Content-Type头指定了UTF-8以外的编码,那么连接管理器MAY在这两中编码中转换,这种转换是OPTIONAL的。在创建session的响应中,连接管理器通过指定可选属性'chartsets',MAY通知客户端哪种编码它可以转换,'chartsets'的值是由空格间隔开的编码方式。
Example 2. 创建session响应
HTTP/1.1 200 OK
charset=utf-8
<body authid='ServerStreamID'
wait='60'
inactivity='30'
polling='5'
requests='2'
accept='deflate,gzip'
sid='SomeSID'
secure='true'
charsets='ISO_8859-1 ISO-2022-JP'
xmlns='http://jabber.org/protocol/httpbind'/>
Note:属性'authid'的值是由XMPP服务生成的stream id的值,连接管理器MUST收到stream id并毫不改变的传给客户端。这个值在客户端进行Non-SASL Authentication验证时传递给连接管理器。(参考下面的jabber:iq:auth章节)
Note:如果属性'authid'不包含在响应中(比如由于连接管理器没有收到stream id),那么客户端SHOULD发送空请求(参考)直到它收到带有'authid'属性的响应。无论如何,在连接管理器收到stream id以后,都MUST在响应中包含'authid'。
区分'sid'和'authid'属性是有必要的,因为连接管理器不是XMPP服务器的必备部分。
如果与XMPP服务器的连接是安全方式的(在上面定义了),那么连接管理器SHOULD在响应中额外指定'secure'的值是'true'或者'1'
8.3 stream features间的联络
连接管理器SHOULD包含一个<stream:features>元素,它是包含有'authid'属性的<body>元素的直接子节点,由RFC 3920中定义。
Example 3. 创建session的响应,带有stream features
HTTP/1.1 200 OK
charset=utf-8
<body authid='ServerStreamID'
wait='60'
inactivity='30'
polling='5'
requests='2'
accept='deflate,gzip'
sid='SomeSID'
charsets='ISO_8859-1 ISO-2022-JP'
xmlns='http://jabber.org/protocol/httpbind'
xmlns:stream='http://etherx.jabber.org/streams'>
<stream:features>
<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>
<mechanism>DIGEST-MD5</mechanism>
<mechanism>PLAIN</mechanism>
</mechanisms>
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'>
<session xmlns='urn:ietf:params:xml:ns:xmpp-session'>
</stream:features>
</body>
stream features SHOULD NOT包含TLS的信息,因为它SHOULD在HTTP层协商(参考下面的安全考虑)。
9,其他准备工作
初始化session是发送XML消息、IQ节等操作的第一项准备工作。在处理来自客户端的XML节之前,连接管理器MUST需要采用下面提供的一种方法进行更多的准备工作:
XMPP验证、资源绑定、IM Session的创建,步骤如下:
可选的,RFC 3920第5章定义的TLS协商(NOT RECOMMENDED)
RFC 3920第6章定义的SASL验证方式
RFC 3920第7章定义的资源绑定
RFC 3921第3章定义的IM Session建立,如果适合的话
在Non-SASL-Authentication中定义的并发的验证和资源绑定,jabber服务同时在连接资源的时候建立IM Session。
RECOMMENDED的是采用RFC 3920和RFC 3921定义的XMPP方式,而非采用旧的Non-SASL-Authentication方式。
9.1 XMPP方式
下面展示了使用XMPP协议成功地进行验证,资源绑定、IM Session建立。有关该协议地更多规定(包括出错情况),以及TLS协商的规定,请参考RFC 3920和RFC 3921。
Example 4. SASL验证,步骤1
charset=utf-8
Content-Length: 172
<body rid='1573741821'
sid='SomeSID'
xmlns='http://jabber.org/protocol/httpbind'>
<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='DIGEST-MD5'/>
</body>
Example 5. SASL验证,步骤2
charset=utf-8
body xmlns='http://jabber.org/protocol/httpbind'>
<challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>
cmVhbG09InNvbWVyZWFsbSIsbm9uY2U9Ik9BNk1HOXRFUUdtMmhoIixxb3A9
ImF1dGgiLGNoYXJzZXQ9dXRmLTgsYWxnb3JpdGhtPW1kNS1zZXNzCg==
</challenge>
</body>
Example 6. SASL验证,步骤3
charset=utf-8
body rid='1573741822'
sid='SomeSID'
xmlns='http://jabber.org/protocol/httpbind'>
<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>
dXNlcm5hbWU9InNvbWVub2RlIixyZWFsbT0ic29tZXJlYWxtIixub25jZT0i
T0E2TUc5dEVRR20yaGgiLGNub25jZT0iT0E2TUhYaDZWcVRyUmsiLG5jPTAw
MDAwMDAxLHFvcD1hdXRoLGRpZ2VzdC275pxk9InhtcHAvZXhhbXBsZS5jb20i
LHJlc3BvbnNlPWQzODhkYWQ5MGQ0YmJkNzYwYTE1MjMyMWYyMTQzYWY3LGNo
YXJzZXQ9dXRmLTgK
</response>
</body>
Example 7. SASL验证,步骤4
charset=utf-8
body xmlns='http://jabber.org/protocol/httpbind'>
<challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>
cnNwYXV0aD1lYTQwZjYwMzM1YzQyN2I1NTI3Yjg0ZGJhYmNkZmZmZAo=
</challenge>
</body>
Example 8. SASL验证,步骤5
charset=utf-8
body rid='1573741823'
sid='SomeSID'
xmlns='http://jabber.org/protocol/httpbind'>
<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/>
</body>
Example 9. SASL验证,步骤6
charset=utf-8
body xmlns='http://jabber.org/protocol/httpbind'>
<success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/>
</body>
Note:由于客户端与连接管理器以http传输绑定,其联络环境是http而不是xml流(在TCP绑定下),所以在此间没有必要重新启动联络。
Example 10. 请求资源绑定
charset=utf-8
body rid='1573741824'
sid='SomeSID'
xmlns='http://jabber.org/protocol/httpbind'>
<iq id='bind_1'
type='set'
xmlns='jabber:client'>
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'>
<resource>httpclient</resource>
</bind>
</iq>
</body>
Example 11. 资源绑定响应结果
charset=utf-8
body xmlns='http://jabber.org/protocol/httpbind'>
<iq id='bind_1'
type='result'
xmlns='jabber:client'>
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'>
<jid>stpeter@jabber.org/httpclient</jid>
</bind>
</iq>
</body>
Example 12. 请求IM Session
charset=utf-8
body rid='1573741825'
sid='SomeSID'
xmlns='http://jabber.org/protocol/httpbind'>
<iq from='stpeter@jabber.org/httpclient'
id='sess_1'
to='jabber.org'
type='set'
xmlns='jabber:client'>
<session xmlns='urn:ietf:params:xml:ns:xmpp-session'/>
</iq>
</body>
charset=utf-8
body xmlns='http://jabber.org/protocol/httpbind'>
<iq from='jabber.org'
id='sess_1'
to='stpeter@jabber.org/httpclient'
type='result'
xmlns='jabber:client'/>
</body>
9.2 jabber:iq:auth
下面展示了使用原始的'jabber:iq:auth'协议成功的并发进行验证、资源绑定、IM Session建立,更详细信息参考XEP-0078。如果使用digest验证,那么stream id MUST是响应的'authid'属性的值相同。
Example 14. Non-SASL authentication请求
charset=utf-8
body rid='1249243561'
sid='SomeSID'
xmlns='http://jabber.org/protocol/httpbind'>
<iq id='A01'
type='set'
xmlns='jabber:client'>
<query xmlns='jabber:iq:auth'>
<username>stpeter</username>
<resource>httpclient</resource>
<password>jabber-rocks</password>
</query>
</iq>
</body>
Example 15. 验证结果(成功)
charset=utf-8
body xmlns='http://jabber.org/protocol/httpbind'>
<iq id='A01'
type='result'
xmlns='jabber:client'/>
</body>
Example 16. 验证结果(失败)
charset=utf-8
body xmlns='http://jabber.org/protocol/httpbind'>
<iq id='A01'
type='error'
xmlns='jabber:client'>
<error code='401' type='auth'>
<not-authorized xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
</error>
</iq>
</body>
10,发送和接收XML节
在客户端成功完成所有的准备工作以后,它就可以通过HTTP绑定来发送和接收XML节了。
Example 17. 传送节
charset=utf-8
body rid='1249243562'
sid='SomeSID'
xmlns='http://jabber.org/protocol/httpbind'>
<message to='contact@example.com'
xmlns='jabber:client'>
<body>Hi there!</body>
</message>
<message to='friend@example.com'
xmlns='jabber:client'>
<body>Hi there!</body>
</message>
</body>
收到请求以后,连接管理器MUST将<body/>元素内容发送到XMPP服务器,而且它必须按照'rid'属性的值有序的发送。
连接管理器也MUST返回一个HTTP 200 OK的响应的<body>元素给客户端。Note:这并不意味着节已经成功的发送到了目标jabber端。
RECOMMENDED的是:从XMPP传送XML节以后,连接管理器再去返回一个HTTP结果。不过,连接管理器等待时间SHOULD NOT超过客户端在创建session请求中指定的'wait'值,并且SHOULD NOT达到超过'hold'值的请求数(同一时间内)。它MUST按照'rid'值有序的响应。
如果等待期内,没有节需要发送(等待发送或者准备发送),那么连接管理器SHOULD在HTTP结果中包含一个空<body/>元素。
Example 18. 有序的响应
charset=utf-8
body xmlns='http://jabber.org/protocol/httpbind'>
<message from='contact@example.com'
to='user@example.com'
xmlns='jabber:client'>
<body>Hi yourself!</body>
</message>
<message from='friend@example.com'
to='user@example.com'
xmlns='jabber:client'>
<body>Hi yourself!</body>
</message>
</body>
客户端可以发送一个空<body/>元素请求,从连接管理器中获得XML节。
Example 19. 请求XML节
charset=utf-8
body rid='1249243563'
sid='SomeSID'
xmlns='http://jabber.org/protocol/httpbind'/>
连接管理器MUST以与收到客户端节时相同的方式等待和响应。
如果客户端在很短的时间(比创建session响应中的'polling'值小)内发送2个连续的空请求,那么连接管理器SHOULD中断(结束)session并且返回一个HTTP 403错误给客户端。
Example 21. 太频繁请求后的响应
charset=utf-8
Content-Length: 0
如果连接管理器在创建session响应时没有指定'polling'值(允许客户端连续空请求的最短时间),那么它MUST允许客户端任意频繁的连续空请求。
在收到连接管理器的响应后,如果没有继续的请求并且客户端没有采用polling形式(在创建session请求中设置'wait'或者'hold'为0),那么客户端SHOULD马上制造一个新的请求。无论如何,如果没有继续的请求,客户端MUST在最大不活跃期终止前制造一个新的请求。最大不活跃期是由创建session响应时'inactivity'属性指定的。
如果连接管理器已经响应了所有它接收到的请求,并且从最后一次响应到当前的这段时间长度超过了最大不活跃期指定的时间长度,那么它SHOULD终止session而不需要通知客户端。(如果客户端之后发出新的请求,连接管理器SHOULD响应session不存在)
如果连接管理器在创建session响应时没有指定最大不活跃期,那么它MUST允许客户端自由地觉得活跃多久。
11,终止HTTP Session
在任何时候,客户端MAY通过发送属性'type'值为'terminate'的<body/>元素来优雅的终止session。终止session的请求SHOULD包含一个XMPP的presence节,它设置属性'type'的值为'unavailable'来退出XMPP服务器。
Example 22. 通过客户端终止session
charset=utf-8
body rid='1249243564'
sid='SomeSID'
type='terminate'
xmlns='http://jabber.org/protocol/httpbind'>
<presence type='unavailable'
xmlns='jabber:client'/>
</body>
连接管理器SHOULD返回一个HTTP 200 OK响应的<body>元素,接收到响应后,客户端MUST认为session已经被终止了。
12,请求标识号
12.1 语法
客户端MUST生成一个大的、随机的、正整数来初始化'rid',并且在随后的一系列请求中,每次对它加1。客户端MUST使得'rid'的值在整个session周期中不会超过9007199254740991。
12.2 有序的消息推进
当一个客户端进行并发的请求,连接管理器可以无序的接收到他们。但是连接管理器MUST发送他们到XMPP服务器以及响应给客户端是有序的(由'rid'得到顺序)。客户端MUST按照请求产生的顺序处理来自连接管理器的响应。
连接管理器SHOULD希望'rid'的值要比之前请求的'rid'值来得大,窗口数目与连接管理器允许的最大并发连接数相同。如果它收到一个请求的'rid'值大于窗口中的值,那么它MUST终止session并发送错误响应。
Example 23. 意外的rid错误
charset=utf-8
Content-Length: 0
12.3 中断连接
靠不住的网络联络以及客户端的各种限制都可以中断连接。连接管理器SHOULD记住'rid'和与最近客户端请求相关的HTTP响应,这请求没有产生HTTP或者绑定错误。保存的这些HTTP响应数量应当与连接管理器允许的最大并发请求数相同。
如果客户端在收到连接管理器的响应之前,网络就已经中断了,客户端MAY重新发送一个相同的原来的请求(是指可以得到之前所说的响应的请求)。连接管理器只要收到请求的'rid'值是曾经已经收到过的,它SHOULD返回一个HTTP 200 OK响应,该响应从其保存的响应中提出。如果原来的响应已经去不到了(不在缓存中),那么连接管理器MUST返回一个HTTP 404错误。
Example 24. 响应不在缓存中
charset=utf-8
Content-Length: 0
Note:该错误信息与'rid'太大或者太小时的错误信息相同。
13,保护不安全的Sessions
13.1 应用性
如果客户端与连接管理器之间的session是不安全的,那么OPTIONAL的key序列MAY被用到。session只有在客户端所有请求通过SSL(或TLS)HTTP连接以及连接管理器产生的SID不可预知的情况下才被认为是安全的。如果session安全,就没有必要使用key序列。
即使session是不安全的,那么不可预知的sid和rid也提供了与采用XMPP的TCP/IP单对连接的安全相似的安全级别,它已经对'blind'攻击提供了充足的保护。不过,在很多情况下,下面讲到的key序列将帮助保护“更聪明”的攻击。
应该清楚的认识到,key序列仅能防止攻击者查看不安全session中的请求与响应,而不能防范变更请求的内容(比如终止请求和响应)
13.2 介绍
每个session的请求MAY扩散到不同的socket连接,这将使一个没有相应验证的用户获得sesion的sid和rid,并且使用他们的socket连接向session插入请求和接收相应的响应。
key序列通过让连接管理器侦测请求的<body/>元素内容来防止第三方进行这样的行为。
13.3 生成key序列
在请求一个新session之前,客户端MUST选定一个不可预知的计数指n和一个不可预知的值seed。客户端接着用cryptographic hash处理这个seed,将产生的160位数转换为16进制的字符串K(1)。重复该操作n次得到一个初始key序列K(n)。这个HASH算法MUST是RFC 3174定义的SHA-1算法。
Example 25. 生成一个key序列
K(1) = hex(SHA-1(seed))
K(2) = hex(SHA-1(K(1)))
...
K(n) = hex(SHA-1(K(n-1)))
13.4 使用key序列
客户端MUST在第一个请求中设置属性'newkey'值为K(n)。
Example 26. 含有初始化key序列的session请求
charset=utf-8
body content='text/xml; charset=utf-8'
hold='1'
rid='1573741820'
to='jabber.org'
wait='60'
xml:lang='en'
newkey='ca393b51b682f61f98e7877d61146407f3d0a770'
xmlns='http://jabber.org/protocol/httpbind'/>
客户端MUST在以后的请求中设置'key'属性值(每次请求的值由前次的K(n-1)变为K(n))。
Example 27. 含有key序列的请求
charset=utf-8
body rid='1573741821'
sid='SomeSID'
key='bfb06a6f113cd6fd3838ab9d300fdb4fe3da2f7d'
xmlns='http://jabber.org/protocol/httpbind'/>
连接管理器MAY使用SHA-1算法验证key值和之前的请求的key/newkey值。如果值不匹配(或者没有收到key属性而在之前的请求中由key/newkey属性),那么连接管理器MUST NOT进行处理,MUST终止session,MUST返回HTTP 404错误。
Example 28. 无效的key序列错误
charset=utf-8
Content-Length: 0
13.5 转换到另一个key序列
在生成key序列时,客户端SHOULD选择一个较大的n值,不过如果session收到的来自客户端来自K(1)中key序列足够久后,那么客户端MUST转换成另一个key序列。
客户端MUST:
选择新的seed和n。
使用上面的算法生成新的key序列。
设置请求的'key'值为旧的序列中应该采用的下一个值。
设置请求的'newkey'值为新的key序列值。
Example 29. 新的key序列
charset=utf-8
body rid='1573741822'
sid='SomeSID'
key='6f825e81f4532b2c5fa2d12457d8a1f22e8f838e'
newkey='113f58a37245ec9637266cf2fb6e48bfeaf7964e'
xmlns='http://jabber.org/protocol/httpbind'>
<message to='contact@example.com'
xmlns='jabber:client'>
<body>Hi there!</body>
</message>
</body>