mirror of https://github.com/moparisthebest/xeps
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
388 lines
16 KiB
388 lines
16 KiB
<?xml version='1.0' encoding='UTF-8'?> |
|
<!DOCTYPE xep SYSTEM 'xep.dtd' [ |
|
<!ENTITY % ents SYSTEM 'xep.ent'> |
|
%ents; |
|
]> |
|
<?xml-stylesheet type='text/xsl' href='xep.xsl'?> |
|
<xep> |
|
<header> |
|
<title>Jabber HTTP Polling</title> |
|
<abstract>This document defines an XMPP protocol extension that enables access to a Jabber server from behind firewalls which do not allow outgoing sockets on port 5222, via HTTP requests.</abstract> |
|
&LEGALNOTICE; |
|
<number>0025</number> |
|
<status>Obsolete</status> |
|
<type>Historical</type> |
|
<sig>Standards</sig> |
|
<dependencies> |
|
<spec>XMPP Core</spec> |
|
</dependencies> |
|
<supersedes/> |
|
<supersededby> |
|
<spec>XEP-0124</spec> |
|
</supersededby> |
|
<shortname>httppoll</shortname> |
|
&hildjj; |
|
<author> |
|
<firstname>Craig</firstname> |
|
<surname>Kaes</surname> |
|
<email>ckaes@jabber.com</email> |
|
<jid>ckaes@corp.jabber.com</jid> |
|
</author> |
|
<author> |
|
<firstname>David</firstname> |
|
<surname>Waite</surname> |
|
<email>mass@akuma.org</email> |
|
<jid>mass@akuma.org</jid> |
|
</author> |
|
<revision> |
|
<version>1.2</version> |
|
<date>2009-06-03</date> |
|
<initials>psa</initials> |
|
<remark><p>Per a vote of the XMPP Council, changed status to Obsolete.</p></remark> |
|
</revision> |
|
<revision> |
|
<version>1.1</version> |
|
<date>2006-07-26</date> |
|
<initials>psa</initials> |
|
<remark><p>Per a vote of the Jabber Council, changed status to Deprecated.</p></remark> |
|
</revision> |
|
<revision> |
|
<version>1.0</version> |
|
<date>2002-10-11</date> |
|
<initials>psa</initials> |
|
<remark><p>Per a vote of the Jabber Council, advanced status to Active.</p></remark> |
|
</revision> |
|
<revision> |
|
<version>0.2</version> |
|
<date>2002-09-23</date> |
|
<initials>dew</initials> |
|
<remark><p>Changed format to allow socket-equivalent security.</p></remark> |
|
</revision> |
|
<revision> |
|
<version>0.1</version> |
|
<date>2002-03-14</date> |
|
<initials>jjh</initials> |
|
<remark><p>Initial version.</p></remark> |
|
</revision> |
|
</header> |
|
<section1 topic="Introduction"> |
|
<p><em>Note Well: This protocol specified in this document has been superseded by the protocol specified in &xep0124;.</em></p> |
|
<p> |
|
This specification documents a method to allow Jabber clients to access Jabber |
|
servers from behind existing firewalls. Although several similar methods |
|
have been proposed, this approach should work through all known firewall |
|
configurations which allow outbound HTTP access. |
|
</p> |
|
</section1> |
|
<section1 topic="Background"> |
|
<p> |
|
In general, a firewall is a box that protects a network from outsiders, |
|
by controlling the IP connections that are allowed to pass through the |
|
box. Often, a firewall will also allow access outside only by proxy, |
|
either explicit proxy support or implicit through Network Address |
|
Translation (NAT). |
|
</p> |
|
<p> |
|
In the interest of security, many firewall administrators do not allow |
|
outbound connections to unknown and unused ports. Until Jabber becomes |
|
more widely deployed, port 5222/tcp (for Jabber client connections) will |
|
often be blocked. |
|
</p> |
|
<p> |
|
The best solution for sites that are concerned about security is to run |
|
their own Jabber server, either inside the firewall, or in a DMZ |
|
<note> |
|
DMZ definition at |
|
<link |
|
url="http://searchwebmanagement.techtarget.com/sDefinition/0,,sid27_gci213891,00.html"> |
|
searchwebmanagement.com |
|
</link> |
|
</note> |
|
network. However, there are network configuration where an external |
|
Jabber server must still be used and port 5222/tcp outbound cannot be |
|
allowed. In these situations, different methods for connecting to a |
|
Jabber server are required. Several methods exist today for doing this |
|
traversal. Most rely on the fact that a most firewalls are configured to |
|
allow access through port 80/tcp. Although some less-complicated |
|
firewalls will allow any protocol to traverse this port, many will proxy, |
|
filter, and verify requests on this port as HTTP. Because of this, a |
|
normal Jabber connection on port 80/tcp will not suffice. |
|
</p> |
|
<p> |
|
In addition, many firewalls/proxy servers will also not allow or not |
|
honor HTTP Keep-alives (as defined in section 19.7.1.1 of &rfc2068;) |
|
and will consider long-lived socket connections as security issues. |
|
Because of this the traditional Jabber connection model, where one |
|
socket is one stream is one session, will not work reliably. |
|
</p> |
|
<p> |
|
In light of all of the ways that default firewall rules can interfere |
|
with Jabber connectivity, a lowest-common denominator approach was |
|
selected. HTTP is used to send XML as POST requests and receieve pending |
|
XML within the responses. Additional information is prepended in the |
|
request body to ensure an equivalent level of security to TCP/IP sockets. |
|
</p> |
|
</section1> |
|
<section1 topic="Normal data transfer"> |
|
<p> |
|
The client makes HTTP requests periodically to the server. Whenever the |
|
client has something to send, that XML is included in the body of the |
|
request. When the server has something to send to the client, it must be |
|
contained in the body of the response. |
|
</p> |
|
<p> |
|
In some browser/platform combinations, sending cookies from the client is |
|
not possible due to design choices and limitations in the |
|
browser. Therefore, a work-around was needed to support clients based on |
|
these application platforms. |
|
</p> |
|
<p> |
|
All requests to the server are HTTP POST requests, with Content-Type: |
|
application/x-www-form-urlencoded. Responses from the server have |
|
Content-Type: text/xml. Both the request and response bodies are UTF-8 |
|
encoded text, even if an HTTP header to the contrary exists. All |
|
responses contain a Set-Cookie header with an identifier, which is sent |
|
along with future requests as described below. This identifier cookie |
|
must have a name of 'ID'. The first request to a server always uses 0 as |
|
the identifier. The server must always return a 200 response code, |
|
sending any session errors as specially-formatted identifiers. |
|
</p> |
|
<p>The client sends requests with bodies in the following format:</p> |
|
<code> |
|
identifier ; key [ ; new_key] , [xml_body] |
|
</code> |
|
<p>If the identifier is zero, key indicates an initial key. In this case, |
|
new_key should not be specified, and must be ignored.</p> |
|
<table caption="Request Values"> |
|
<tr> |
|
<th>Identifier</th> |
|
<th>Purpose</th> |
|
</tr> |
|
<tr> |
|
<td>identifier</td> |
|
<td> |
|
To uniquely identify the session server-side. This field is only |
|
used to identify the session, and provides no security. |
|
</td> |
|
</tr> |
|
<tr> |
|
<td>key</td> |
|
<td> |
|
To verify this request is from the originator of the session. The |
|
client generates a new key in the manner described below for each |
|
request, which the server then verifies before processing the |
|
request. |
|
</td> |
|
</tr> |
|
<tr> |
|
<td>new_key</td> |
|
<td> |
|
The key algorithm can exhaust valid keys in a sequence, which |
|
requires a new key sequence to be used in order to continue the |
|
session. The new key is sent along with the last used key in the |
|
old sequence. |
|
</td> |
|
</tr> |
|
<tr> |
|
<td>xml_body</td> |
|
<td> |
|
The body of text to send. Since a POST must be sent in order for |
|
the server to respond with recent messages, a client may send |
|
a request without an xml_body in order to just retrieve new |
|
incoming packets. This is not required to be a full XML document or |
|
XML fragment, it does not need to start or end on element boundaries. |
|
</td> |
|
</tr> |
|
</table> |
|
<p> |
|
The identifier is everything before the first semicolon, and must consist |
|
of the characters [A-Za-z0-9:-]. The identifier returned from the first |
|
request is the identifier for the session. Any new identifier that ends |
|
in ':0' indicates an error, with the entire identifier indicating the |
|
specific error condition. Any new identifier that does not end in ':0' is |
|
a server programming error, the client should discontinue the |
|
session. For new sessions, the client identifier is considered to be 0. |
|
</p> |
|
<section2 topic="Error conditions"> |
|
<p> |
|
Any identifier that ends in ':0' indicates an error. Any previous |
|
identifier associated with this session is no longer valid. |
|
</p> |
|
<section3 topic="Unknown Error"> |
|
<p> |
|
Server returns ID=0:0. The response body can contain a textual error |
|
message. |
|
</p> |
|
</section3> |
|
<section3 topic="Server Error"> |
|
<p>Server returns ID=-1:0</p> |
|
</section3> |
|
<section3 topic="Bad Request"> |
|
<p>Server returns ID=-2:0</p> |
|
</section3> |
|
<section3 topic="Key Sequence Error"> |
|
<p>Server returns ID=-3:0</p> |
|
</section3> |
|
</section2> |
|
<p> |
|
The key is a client security feature to allow TCP/IP socket equivalent |
|
security. It does not protect against intermediary attacks, but does |
|
prevent a person who is capable of listening to the HTTP traffic from |
|
sending messages and receiving incoming traffic from another machine. |
|
</p> |
|
<p>The key algorithm should be familiar with those with knowledge of Jabber zero-knowledge authentication.</p> |
|
<code> |
|
K(n, seed) = Base64Encode(SHA1(K(n - 1, seed))), for n > 0 |
|
K(0, seed) = seed, which is client-determined |
|
</code> |
|
<p>Note: Base64 encoding is defined in &rfc3548;. SHA1 is defined in &rfc3174;.</p> |
|
<p> |
|
No framing is implied by a single request or reply. A single request can |
|
have no content sent, in which case the body contains only the identifier |
|
followed by a comma. A reply may have no content to send, in which case |
|
the body is empty. Zero or more XMPP packets may be sent in a single |
|
request or reply, including partial XMPP packets. |
|
</p> |
|
<p> |
|
The absense of a long-lived connection requires the server to consider |
|
client traffic as a heartbeat to keep the session alive. If a |
|
server-configurable period of time passes without a successful POST |
|
request sent by the client, the server must end the client session. Any |
|
client requests using the identifier associated with that now dead |
|
session must return an error of '0:0'. |
|
</p> |
|
<p> |
|
The maximum period of time to keep a client session active without an |
|
incoming POST request is not defined, but five minutes is the recommended |
|
minimum. The maximum period of time recommended for clients between |
|
requests is two minutes; if the client has not sent any XML out for two |
|
minutes, a request without an XML body should be sent. If a client is |
|
disconnecting from the server, a closing <stream:stream> must be |
|
sent to end the session. Failure to do this may have the client continue |
|
to be represented to other users as available. |
|
</p> |
|
<p> |
|
If the server disconnects the user do to a session timeout, the server |
|
MUST bounce pending IQ requests and either bounce or store offline |
|
incoming messages. |
|
</p> |
|
</section1> |
|
<section1 topic="Usage"> |
|
<p>The following is the sequence used for client communication:</p> |
|
<ol> |
|
<li> |
|
The client generates some initial K(0, seed) and runs the algorithm |
|
above 'n' times to determine the initial key sent to the server, |
|
K(n, seed) |
|
</li> |
|
<li> |
|
The client sends the request to the server to start the stream, |
|
including an identifier with a value of zero and K(n, seed) |
|
</li> |
|
<li> |
|
The server responds with the session identifier in the headers |
|
(within the Set-Cookie field). |
|
</li> |
|
<li> |
|
For each further request done by the client, the identifier from the |
|
server and K(n - 1, seed) are sent along. |
|
</li> |
|
<li> |
|
The server verifies the incoming value by generating |
|
K(1, incoming_value), and verifying that value against the value sent |
|
along with the last client request. If the values do not match, the |
|
request should be ignored or logged, with an error code being |
|
returned of -3:0. The request must not be processed, and must not |
|
extend the session keepalive. |
|
</li> |
|
<li> |
|
The client may send a new key K(m, seed') at any point, but should |
|
do this for n > 0 and must do this for n = 0. If K(0, seed) is |
|
sent without a new key, the client will not be able to continue the |
|
session. |
|
</li> |
|
</ol> |
|
<example caption="Initial request (without keys)"> |
|
|
|
<![CDATA[POST /wc12/webclient HTTP/1.1 |
|
Content-Type: application/x-www-form-urlencoded |
|
Host: webim.jabber.com |
|
|
|
0,<stream:stream to="jabber.com" |
|
xmlns="jabber:client" |
|
xmlns:stream="http://etherx.jabber.org/streams">]]> |
|
|
|
</example> |
|
<example caption="Initial response"> |
|
|
|
<![CDATA[Date: Fri, 15 Mar 2002 20:30:30 GMT |
|
Server: Apache/1.3.20 |
|
Set-Cookie: ID=7776:2054; path=/webclient/; expires=-1 |
|
Content-Type: text/xml |
|
|
|
<?xml version='1.0'?> |
|
<stream:stream xmlns:stream='http://etherx.jabber.org/streams' |
|
id='3C9258BB' |
|
xmlns='jabber:client' from='jabber.com'>]]> |
|
|
|
</example> |
|
<example caption="Next request (without keys)"> |
|
|
|
<![CDATA[POST /wc12/webclient HTTP/1.1 |
|
Content-Type: application/x-www-form-urlencoded |
|
Host: webim.jabber.com |
|
|
|
7776:2054,<iq type="get" id="WEBCLIENT3"> |
|
<query xmlns="jabber:iq:auth"> |
|
<username>hildjj</username> |
|
</query> |
|
</iq>]]> |
|
|
|
</example> |
|
<example caption='key sequence'> |
|
K(0, "foo") = "foo" |
|
K(1, "foo") = "C+7Hteo/D9vJXQ3UfzxbwnXaijM=" |
|
K(2, "foo") = "6UU8CDmH3O4aHFmCqSORCn721+M=" |
|
K(3, "foo") = "vFFYSOhGyaGUgLrldtMBX7x91Wc=" |
|
K(4, "foo") = "ZaDxCilBVTHS9dJfbBo1NsC2b+8=" |
|
K(5, "foo") = "moPFsvHytDGiJQOjp186AMXAeP0=" |
|
K(6, "foo") = "VvxEk07IFy6hUmG/PPBlTLE2fiA=" |
|
</example> |
|
<example caption="Initial request (with keys)"> |
|
|
|
<![CDATA[POST /wc12/webclient HTTP/1.1 |
|
Content-Type: application/x-www-form-urlencoded |
|
Host: webim.jabber.com |
|
|
|
0;VvxEk07IFy6hUmG/PPBlTLE2fiA=,<stream:stream to="jabber.com" |
|
xmlns="jabber:client" |
|
xmlns:stream="http://etherx.jabber.org/streams">]]> |
|
|
|
</example> |
|
<example caption="Next request (with keys)"> |
|
|
|
<![CDATA[POST /wc12/webclient HTTP/1.1 |
|
Content-Type: application/x-www-form-urlencoded |
|
Host: webim.jabber.com |
|
|
|
7776:2054;moPFsvHytDGiJQOjp186AMXAeP0=,<iq type="get" id="WEBCLIENT3"> |
|
<query xmlns="jabber:iq:auth"> |
|
<username>hildjj</username> |
|
</query> |
|
</iq>]]> |
|
|
|
</example> |
|
<example caption='Changing key'> |
|
<![CDATA[POST /wc12/webclient HTTP/1.1 |
|
Content-Type: application/x-www-form-urlencoded |
|
Host: webim.jabber.com |
|
|
|
7776:2054;C+7Hteo/D9vJXQ3UfzxbwnXaijM=;Tr697Eff02+32FZp38Xaq2+3Bv4=,<presence/>]]> |
|
</example> |
|
</section1> |
|
<section1 topic="Known issues"> |
|
<ul> |
|
<li>This method works over HTTPS, which is good from the standpoint of functionality, but bad in the sense that a massive amount of hardware would be needed to support reasonable polling intervals for non-trivial numbers of clients.</li> |
|
</ul> |
|
</section1> |
|
</xep>
|
|
|