翻译XEP-0124: HTTP Binding(转)

这个文档定义了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连接一样的工作。
  1. 与有局限的运行环境的兼容。
  2. 与有局限的网络连接的兼容。
  3. 故障的恢复。
  4. 可扩展性。
  5. 更少的带宽消耗。
  6. 更多的响应。
  7. 支持polling
  8. 客户端发送的XML节有序的进入服务端。
  9. 防止恶意地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的创建,步骤如下:

  1. 可选的,RFC 3920第5章定义的TLS协商(NOT RECOMMENDED

  2. RFC 3920第6章定义的SASL验证方式

  3. RFC 3920第7章定义的资源绑定

  4. 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
MDAwMDAxLHFvcD1hdXRoLGRpZ2VzdC11cmk9InhtcHAvZXhhbXBsZS5jb20i
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:
  1. 选择新的seed和n。
  2. 使用上面的算法生成新的key序列。
  3. 设置请求的'key'值为旧的序列中应该采用的下一个值。
  4. 设置请求的'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>

14,多个流

    14.1 介绍

本章描述的
OPTIONAL特性将使单一的HTTP session能够包含多个XMPP流。在限制客户端并发发送请求数量的环境下,该特性是必要的,因为如果客户端同时打开多个帐号,就需要多-流sessions。这个特性使得客户端在HTTP上建立平行的流时降低网络的传输量。

    14.2 展开

        如果连接管理器支持多-流特性,它在创建session响应时MUST包含'stream'属性。如果客户端没有收到'stream'属性,那么它MUST假定连接管理器不支持该特性。

        'stream'属性指定了session需要打开的第一个流。每个'stream'的值MUST是一个不透明的、不可预知的名字,在连接管理器应用中是唯一的。


        Example 30. 创建session响应,带有stream名字
 charset=utf-8
body authid='ServerStreamID'
wait='60'
inactivity='30'
polling='5'
requests='2'
accept='deflate,gzip'
sid='SomeSID'
secure='true'
stream='firstStreamName'
charsets='ISO_8859-1 ISO-2022-JP'
xmlns='http://jabber.org/protocol/httpbind'/>
    14.3 对一个Session新增流

        如果连接管理器在创建session响应时包含了'stream'属性,那么客户端可以发送一个带有'to'属性的空<body/>元素来请求连接管理器打开另外一个流。该请求MUST包含有效的'sid'和'rid'属性,它SHOULD包含'xml:lang'属性。请求MAY包含'route'和'secure'属性,但SHOULD NOT包含'content','hold'或者'wait'属性。

        Example 31. 请求另外一个流
 charset=utf-8
body sid='SomeSID'
rid='1573741820'
to='jabber.org'
route='xmpp:jabber.org:9999'
secure='true'
xml:lang='en'
xmlns='http://jabber.org/protocol/httpbind'/>
        如果连接管理器在session开始时没有指定它支持多流,那么它MUST忽略额外的属性,只当其是一个普通的空请求(参考发送和接收XML节)。否则,它MUST对服务器打开一个新的流(参考创建session),生成一个新的流名字并响应给客户端。响应MAY包含'authid'和'secure'属性,但是它SHOULD NOT包含'sid', 'requests', 'polling', 'inactivity', 'accept', 'charsets' 或者 'wait'属性。

        Example 32. 新增流的响应
 charset=utf-8
body stream='secondStreamName'
authid='ServerStreamID'
secure='true'
xmlns='http://jabber.org/protocol/httpbind'/>
        Note:如果响应没有'authid'属性,那么其他属性MUST由之后的响应发送(参考创建session),'stream'属性也要被指定。

    14.4 节的传输

        如果一个session打开的流数目大于一个,那么连接管理器发送的所有非空<body>元素MUST包含‘stream’以指出它发送的节是属于哪个流的。相同的原因,客户端也SHOULD包含‘stream’属性。客户端MAY忽略‘stream’属性使连接管理器在所有打开的流上发送节。Note:一个<body/>元素MUST NOT含有针对不同流的不同节。

        如果流的名字没有与session打开的流的某个名字相同,那么接收流的连接管理器SHOULD返回一个HTTP 404错误,或者接收流的客户端SHOULD终止session。如果接收者仅仅是关闭流(发送者在发送节的时候不可能注意到这情况),那么接受者只要简单的忽略<body/>元素包含的节就可以了。

        Note:不包含'authid'属性的<body/>元素SHOULD NOT包含'stream'属性(因为没有任何信息要在流中传输)。如果这样的一个<body/>元素包含了'stream'属性,那么接收者SHOULD忽略该属性。


        Example 33. 客户端发送的节,带有流的名字

 charset=utf-8
body rid='1249243562'
sid='SomeSID'
stream='secondStreamName'
xmlns='http://jabber.org/protocol/httpbind'>
<message to='contact@example.com'
xmlns='jabber:client'>
<body>Hi there!</body>
</message>
</body>
        Note:响应的‘stream’属性的值MAY与对应请求的值不同。

        Example 34. 连接管理器以不同的流名字响应
 charset=utf-8
body stream='firstStreamName'
xmlns='http://jabber.org/protocol/httpbind'>
<message from='contact@example.com'
to='user@example.com'
xmlns='jabber:client'>
<body>Hi yourself!</body>
</message>
</body>
        如果连接管理器没有指定流的名字,那么客户端MUST假定收到的节是与第一个流名字有关的信息(甚至在第一个流被关闭了也这样认为)。

        如果客户端没有指定流的名字,那么连接管理器MUST在所有打开的流上发送节。


        Example 35. 客户端请求一个节被发送(所有流上)
 charset=utf-8
body rid='1249243562'
sid='SomeSID'
xmlns='http://jabber.org/protocol/httpbind'>
<presence xmlns='jabber:client'>
<show>away</show>
</presence>
</body>
    14.5 关闭一个流

        如果一个session打开了多个流,客户端MAY在任何时候使用由终止HTTP Session中描述的方法关闭一个打开的流,要由‘stream’属性指定一个流名字。如果客户端关闭了最后一个流,连接管理器MUST终止session。如果客户端没有指定流名字,那么连接管理器MUST关闭所有打开的流(所有流发送终止请求),并且终止session。


        Example 36. 客户端关闭一个流
 charset=utf-8
body rid='1249243564'
sid='SomeSID'
stream='secondStreamName'
type='terminate'
xmlns='http://jabber.org/protocol/httpbind'>
<presence type='unavailable'
xmlns='jabber:client'/>
</body>

    14.6 错误情形

        如果一个session打开多个流,在失败的绑定错误中(
参考终止绑定情况 )连接管理器MAY包含‘stream’属性。如果‘stream’属性设置了,那么接收和发送端都MUST关闭流,但是session SHOULD NOT被终止。

        Example 37. 失败的流错误
 charset=utf-8
body type='terminate'
condition='remote-connection-failed'
stream='secondStreamName'
xmlns='http://jabber.org/protocol/httpbind'/>
        Note:如果在失败的绑定错误时,连接管理器不包含'stream'属性,那么session所有的流都要在接收和发送两端被关闭,session也MUST被终止。

15,错误和状态码

        在HTTP响应中有4种错误和状态

        表1:错误类型

Condition TypeDescription
HTTP Conditions连接管理器对无效的客户端请求返回一个标准的HTTP error响应。无效的请求包括绑定语法错误,可能的攻击等。注意,受限制的客户端不能区别HTTP errors的区别。
Terminal Binding Conditions这类错误可能由受限制的客户端读取到。用于连接管理器产生的问题,流问题以及连接管理器与XMPP服务器联络的问题。
Recoverable Binding Conditions用于在连接管理器和客户端之间联络的问题。这种情况不需要终止session。客户端只要通过重新发送之前没有被响应的<body/>元素就可以恢复正常。
XMPP Stanza ConditionsXMPP错误是与<body/>元素中XML节相关的,一般来说,由RFC或者XEP给出相应的情形。这种情况不需要终止session。(上面jabber:iq:auth给出了这样的一个例子。)
   
        详细描述由下面提供
    
        15.1 HTTP状况

        下面给出的错误和状态码在本协议中有特别的意义(其他错误和状态码还是其本身的意义)。在收到HTTP 错误(400,403,404)时,HTTP客户端MUST认为HTTP session是空的。

        Note:这些HTTP码都是在HTTP规范中定义的。在使用Jabber协议时,不要与传统的HTTP错误相混淆。


        表2:HTTP错误和状态码
   
CodeNamePurpose
200OK客户端请求的有效响应。
400Bad Request通知客户端HTTP头和绑定元素的格式是不被接受的。(比如,语法错误).
403Forbidden通知客户端它的请求不符合session的规则。(比如,请求太频繁,太多的并发连接)。
404Not Found通知客户端:(1) 'sid'是无效的, (2) 'stream'是无效的, (3) 'rid'值超过了希望的窗口数, (4) 连接管理器不能重新发送响应,(5) 'key'序列无效。

        15.2 终止绑定情况

        对于任意发送给客户端的响应,连接管理器MAY通过设置<body/>元素的属性‘type’值为‘terminate’来返回一个失败错误。这个错误暗示HTTP session被终止了(除非指定了‘stream’属性,参考多个流-错误情形)。(这种错误大 多数也意味着 RFC 3920定义的XMPP流错误,不过实际上在连接管理器与服务器之间的XMPP流错误是一个“remote-stream-error ”,在下面有描述)。

        Example 38. 远端连接失败的错误
 charset=utf-8
body type='terminate'
condition='remote-connection-failed'
xmlns='http://jabber.org/protocol/httpbind'/>
        属性‘condition’值的定义如下。

        表3:绑定错误情形
  
ConditionPurpose
host-gone属性‘to’指定的目标域或者属性‘route’指定的主机或者端口不在提供服务了。
host-unknown连接管理器无法获知属性‘to’指定的目标域或者属性‘route’指定的主机或者端口。
improper-addressing初始化元素缺少‘to’或者‘route’属性(或者属性没值),但是连接管理器需要其中之一。
internal-server-error连接管理器收到一个内部错误,阻止其响应请求。
other-request在请求终止session的时候,另一个请求正在被处理。
remote-connection-failed连接管理器对XMPP服务器不能够连接、不能安全的连接、或者失去连接。
remote-stream-error压缩一个XMPP流出错。流内容是一个从XMPP服务器接收到的<stream:error/>元素。
see-other-uri在一个URI上(比如,连接管理器仅接收客户端在一些https:URI上的SSL或者TLS连接,而不支持在http:URI上的),连接管理器不能进行操作。客户端可以在<uri/>子元素的内容中post内容。
system-shutdown连接管理器即将关闭。所有活动的sessions都要被终止。不能创建新的sessions。
undefined-condition未在此定义的错误。连接管理器SHOULD在<body/>元素内容中包含一个应用程序指定的信息。
  
        下面是一个
"see-other-uri" 情形的例子:

        Example 39. see-other-uri的错误
 charset=utf-8
body condition='see-other-uri'
type='terminate'
xmlns='http://jabber.org/protocol/httpbind'>
<uri>https://secure.jabber.org/xmppcm</uri>
</body>
        下面是一个"remote-stream-error"情形的例子:

        Example 40. 远端错误
 charset=utf-8
body condition='remote-stream-error'
type='terminate'
xmlns='http://jabber.org/protocol/httpbind'>
<xml-not-well-formed xmlns='urn:ietf:params:xml:ns:xmpp-streams'/>
<text xmlns='urn:ietf:params:xml:ns:xmpp-streams'
xml:lang='en'>
Some special application diagnostic information!
</text>
<escape-your-data xmlns='application-ns'/>
</body>
        当然,客户端也MAY通知连接管理器绑定错误,尽管这未必会有。

        15.3 可恢复绑定情况

        对于任意发送给客户端的响应,连接管理器MAY通过设置<body/>元素中属性'type'值为'error'来发送一个可恢复的错误。这种错误并不指session已经终止了。

        如果决定从错误中恢复,那么客户端MUST重复发送HTTP请求以及之前所有没有收到响应的HTTP请求。这些请求的内容MUST与之前请求的<body/>元素内容相同。这就允许连接管理器由于联络失败而错过之前请求以后,可以恢复。

        Example 41. 可恢复的错误
 charset=utf-8
body type='error'
xmlns='http://jabber.org/protocol/httpbind'/>

    15.4 XMPP节的情况

        应用级别的错误通常是由第3方产生的并且由连接管理器传递到客户端,因此他们就超出了这里定义的范围,他们在RFC或者XEP中有更详细的描述。

        然而,连接管理器有可能收到一个需要发送到客户端的节,但是客户端的连接已经不在激活状态(比如在连接管理器要通知服务器该连接不在激活之前)。在此时,连接管理器要向服务器发送一个错误。由于这种情况与RFC 3920 11.1章定义的类似,因此
RECOMMENDED连接管理器按照下面的做:
  1. 如果是<presence/>节,那么丢掉节,不必要向服务器发送错误。
  2. 如果是<iq/>节,那么向服务器返回<service-unavailable/>错误。
  3. 如果是<message/>节,那么向服务器返回<recipient-unavailable/>错误。
        当服务器从连接管理器处收到一个带有<recipient-unavailable/>错误的<message/节>时,它SHOULD保存这些信息(不在线状态下允许发送消息),而不只是单单的将错误节传输给它。

16,实施备忘录

        这里想象的只是将这个协议的实现作为XMPP服务器的一个连接管理器,也可能实现一个没有XMPP实现的连接管理。而且,它也可以简单的扮演处理XML结构的角色。因此在这定义的XML schemas不仅仅是针对XMPP服务器端的,使用连接管理器的应用程序应有责任处理这些错误,而不是连接管理器。

17,安全考虑


        联络SHOULD在一个加密的HTTP连接上进行。客户端和连接管理器直接的加密协商SHOULD在传输层或HTTP层进行。这个协商SHOULD遵循SSL定义的HTTP/SSL协议,它MAY遵循RFC 2818定义的HTTP/TLS协议或者RFC 2817定义的HTTP协议中的TLS。

        如果发送初始化session请求的连接是加密的,那么这个session的所有连接SHOULD都是加密的。如果验证检定在建立加密的连接(用来发送初始化session请求)中互换,客户端和/或连接管理器SHOULD确保相同的验证检定在session以后用到的连接中也被使用。一旦这样一个‘安全的session’建立好:
  • 如果连接管理器拒绝建立一个加密的连接或者提供不同检定,那么客户端SHOULD关闭连接和终止session,无需发送其他请求。
  • 如果客户端在连接(没有加密或者检定不同)中发送一个封装好的元素(是安全的session中的一部分),那么连接管理器SHOULD只要关闭连接,而SHOULD NOT终止session,因为这样已经可以帮助拒绝攻击了。

        SID和RID是重要的安全因素,所以它们MUST是不可预知和不重复的(参考RFC 1750针对产生随机sid和rid的建议)。

        当连接管理器独立于XMPP服务器作为一个代理时,它又有其他的安全漏洞。RECOMMENDED是:客户端通过加密确保发送的节的安全性(参考xep0116-加密的session)。


        18,IANA考虑

        参考IANA(
The Internet Assigned Numbers Authority

19,XMPP登记考虑

    19.1 协议命名空间

        参考XMPP登陆xep-0053

20,XML Schema


结束!这里是原文档。

原文转自:http://www.blogjava.net/howard/archive/2006/12/04/85309.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值