XMPP包含的一个保证流安全的方法(传输层安全协议[TLS]的频道加密方法)来防止篡改和偷听.
一个给定域的管理员可以要求客户端和服务器通信以及服务器之间通信时使用TLS,或者两者都要求。客户端应该在尝试完成 SASL握手之前使用 TLS,服务器应该在两个域之间使用 TLS 以保证服务器间通信的安全。
当一个初始化实体用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_123' from='example.com' version='1.0'>
步骤3:服务器发送 STARTTLS 范围给客户端(包括验证机制和任何其他流特性)
<stream:features> <starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'> <required/> </starttls> <mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'> <mechanism>DIGEST-MD5</mechanism> <mechanism>PLAIN</mechanism> </mechanisms> </stream:features>
步骤4:客户端发送 STARTTLS 命令给服务器
<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>
步骤5:服务器通知客户端可以继续进行
<proceed xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>
步骤 5 (或者): 服务器通知客户端 TLS 握手失败并关闭流和TCP连接
<failure xmlns='urn:ietf:params:xml:ns:xmpp-tls'/> </stream:stream>
步骤 6: 客户端和服务器尝试通过已有的TCP连接完成 TLS 握手.
步骤 7: 如果 TLS 握手成功, 客户端初始化一个新的流给服务器
<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' from='example.com' id='c2s_234' version='1.0'> <stream:features> <mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'> <mechanism>DIGEST-MD5</mechanism> <mechanism>PLAIN</mechanism> <mechanism>EXTERNAL</mechanism> </mechanisms> </stream:features>
步骤 9: 客户端继续 SASL 握手
步骤1:Server1 初始化流给 Server2
<stream:stream xmlns='jabber:server' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'>
步骤2:Server2 发送一个流标签给 Server1 作为应答
<stream:stream xmlns='jabber:server' xmlns:stream='http://etherx.jabber.org/streams' from='example.com' id='s2s_123' version='1.0'>
步骤3:Server2 发送 STARTTLS 范围给 Server1 ,包括验证机制和任何其他流特性
<stream:features> <starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'> <required/> </starttls> <mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'> <mechanism>DIGEST-MD5</mechanism> <mechanism>KERBEROS_V4</mechanism> </mechanisms> </stream:features>
步骤 4: Server1 发送 STARTTLS 命令给 Server2
<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>
步骤5:Server2 通知 Server1 允许继续进行
<proceed xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>
步骤 6: Server1 和 Server2 尝试通过 TCP 完成 TLS 握手.
步骤 7: 如果 TLS 握手成功, Server1 初始化一个新的流给 Server2
<stream:stream xmlns='jabber:server' xmlns:stream='http://etherx.jabber.org/streams' to='example.com' version='1.0'>
步骤7(或者): 如果 TLS 握手不成功, Server2 关闭 TCP 连接.
步骤8 : Server2 发送一个包含任何可用流特性的流头信息给 Server1
<stream:stream xmlns='jabber:server' xmlns:stream='http://etherx.jabber.org/streams' from='example.com' id='s2s_234' version='1.0'> <stream:features> <mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'> <mechanism>DIGEST-MD5</mechanism> <mechanism>KERBEROS_V4</mechanism> <mechanism>EXTERNAL</mechanism> </mechanisms> </stream:features>
步骤9:Server1 继续进行 SASL 握手
XMPP 有一个验证流的方法,即XMPP特定的SASL(简单验证和安全层)[SASL]。SASL提供了一个通用的方法为基于连接的协议增加验证支持,而XMPP使用了一个普通的XML名字空间来满足SASL的需要。
一个初始化实体使用SASL和接收实体做验证的步骤如下:
步骤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'> cmVhbG09InNvbWVyZWFsbSIsbm9uY2U9Ik9BNk1HOXRFUUdtMmhoIixxb3A9ImF1dGgiLGNoYXJzZXQ9dXRmLTgsYWxnb3JpdGhtPW1kNS1zZXNzCg== </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>
步骤 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/>
PS:资源文件来自Jabber /XMPP中文翻译计划