美文网首页
XMPP通讯安全--SASL协议学习

XMPP通讯安全--SASL协议学习

作者: 悟笃笃 | 来源:发表于2018-09-15 22:00 被阅读245次

在使用smack开发聊天功能的时候,对XMPP协议中使用TLS和SSAL协议保证通讯安全的知识进行学习和记录。文章中的smack版本是V4.2.4,openfire服务器是V4.2.3.

TLS和SASL的作用

  • TLS:全称是Transport Layer Security(安全传输层协议),最为我们熟知的就是HTTPS,便是HTTP+TLS(SSL)组合而成的。而客户端和openfire服务器的连接也是一个TCP链接,这里我们在使用smack 的API的时候通过连接类名XMPPTCPConnection就可得知。
  • SSAL:这是一个鉴权协议,主要用来保证客户端登录服务器时候传输的鉴权数据的安全性。

所以,我们可以得知TLS是对整个传输过程的加密,SASL只是对于鉴权数据的加密。如果要和openfire服务器使用TLS协议进行连接,正常情况下是需要到掏钱CA机构登记。
因为是出于学习目的,我们也可以使用自签名的证书去验证。对于使用TLS连接会在下篇文章写到,这篇文章先写使用不同SASL机制的登录报文分析学习。

SASL

假如在smack中配置xmpp连接的时候只使用了SASL没有使用TLS,那么除了账号密码登录之外,我们的所有通讯内容都是裸奔!

SASL全拼是Simple Authentication and Security Layer,是一种用来扩充C/S模式验证能力的机制,是一种鉴权协议,制定了鉴权数据的交换,但是并没有制定数据的内容。不同于与TLS&SSL这种协议,TLS&SSL是对整个传输通道全部数据加密,具体的加密过程和HTTPS类似,不去改变HTTP协议及其传输内容,只是在C和S之间对了认证、加密、解密等过程。
在XMPP协议中,SASL是使用一个简单的xml命名空间来完成的鉴权协议,需要服务器和客户端在连接建立的开始去确认采用何种加密方式。这里先说一下smack中默认支持多少种SASL加密机制,及其特性。

默认的SASL机制

下面这几种加密机制,被初始化在SASLAuthentication.REGISTERED_MECHANISMS容器中,我们可以手动实现SASL机制注册进去,客户端采用何种SASL的机制是根据该容器中的顺序。
这里先不拿具体报文去解析,会增加理解难度,先解释不同SASL机制的不同特性再去查看客户端连接服务器的报文

  • PLAIN:对鉴权数据Base64编码后传输,相当于明文传输。假如传输登录密码,那就是登录密码BASE64以后传输而已,不配合TLS对传输数据进行加密处理就等同于裸奔了,密码都告诉别人了。
  • ANONYMOUS:看具体的实现类的关键方法均是空实现,这块的知识以后补充
  • EXTERNAL:采用这种SASL鉴权机制,用户名可以为空,并且同SSL进行验证连接安全性
  • X-OAUTH2:这种鉴权机制,密码会以开放授权的方式 进行验证。是谷歌大佬定义的,建议不要使用。在SASLXOauth2Mechanism的注释中是有注明不建议使用的原因的
  • SCRAM-SHA-1-PLUS:加密机制,墙裂建议使用
  • SCRAM-SHA-1:加密机制,墙裂建议使用
  • DIGEST-MD5:加密机制,墙裂建议使用

以上的几种加密机制,建议使用SCRAM-SHA-1-PLUS,SCRAM-SHA-1DIGEST-MD5。在最新的smack库中,如果服务器全部支持,框架会自动选择SCRAM-SHA-1,而至于PLAIN不建议使用,对于鉴权数据(登录密码)只进行了Base64加密以后传输。

连接openfire服务器的报文解析

SENT表明是客户端发送的报文,RECV是服务器返回的。
这里采用的PLAIN去连接openfire服务器,观察分析报文内容再对SASL的鉴权进行进一步学习了解

    //配置SASL机制黑名单,让客户端采用PLAIN机制鉴权
    SASLAuthentication.blacklistSASLMechanism(SASLAnonymous.NAME);
    SASLAuthentication.blacklistSASLMechanism(SASLXOauth2Mechanism.NAME);
    SASLAuthentication.blacklistSASLMechanism(SASLExternalMechanism.NAME);
    SASLAuthentication.blacklistSASLMechanism(SCRAMSHA1Mechanism.NAME);
    SASLAuthentication.blacklistSASLMechanism(ScramSha1PlusMechanism.NAME);
    SASLAuthentication.blacklistSASLMechanism(SASLDigestMD5Mechanism.NAME);

客户端连接服务器

    //客户端请求连接服务器
    SENT (0):
        <stream:stream xmlns='jabber:client' to='127.0.0.1' xmlns:stream='http://etherx.jabber.org/streams' version='1.0' xml:lang='en'>
    //服务器返回,告知客户端的id
    RECV (0): 
        <?xml version="1.0" encoding="utf-8"?>
            <stream:stream xmlns:stream="http://etherx.jabber.org/streams" xmlns="jabber:client" from="127.0.0.1" id="196jv2n3s5" xml:lang="en" version="1.0"/>
    //鉴权验证阶段,在mechanisms标签中,告知客户端openfire服务器支持多少种mechanism,由客户端自行选择适合的mechanism进行鉴权操作
    //compression标签告知客户端,服务器的压缩方法,
    RECV (0): 
        <stream:features>
          <starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"></starttls>
          <mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl">
            <mechanism>PLAIN</mechanism>
            <mechanism>SCRAM-SHA-1</mechanism>
            <mechanism>CRAM-MD5</mechanism>
            <mechanism>DIGEST-MD5</mechanism>
          </mechanisms>
          <compression xmlns="http://jabber.org/features/compress">
            <method>zlib</method>
          </compression>
          <ver xmlns="urn:xmpp:features:rosterver"></ver>
          <register xmlns="http://jabber.org/features/iq-register"></register>
        </stream:features>

鉴权过程

    
    //采用PLAIN,直接把账号名和密码Base64编码以后,打包发送。打包的实现看SASLMechanism.getAuthenticationText()方法
    SENT (0):
        <auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='PLAIN'>AHd6aAAxMjM0NTY=</auth>
    //success表明鉴权成功
    RECV (0):
        <success xmlns="urn:ietf:params:xml:ns:xmpp-sasl"/>

握手

        
    //客户端发送一个带有id的请求
    SENT (0):
        <stream:stream xmlns='jabber:client' to='127.0.0.1' xmlns:stream='http://etherx.jabber.org/streams' version='1.0' id='196jv2n3s5' xml:lang='en'>
    //服务器回应待会一些参数
    RECV (0):
        <?xml version='1.0' encoding='utf-8'?>
        <stream:stream xmlns:stream="http://etherx.jabber.org/streams" xmlns="jabber:client" from="127.0.0.1" id="196jv2n3s5" xml:lang="en" version="1.0">
                <stream:features>
                    <compression xmlns="http://jabber.org/features/compress">
                        <method>zlib</method>
                    </compression>
                    <ver xmlns="urn:xmpp:features:rosterver" />
                    <bind xmlns="urn:ietf:params:xml:ns:xmpp-bind" />
                    <session xmlns="urn:ietf:params:xml:ns:xmpp-session">
                        <optional />
                    </session>
                    <sm xmlns='urn:xmpp:sm:2' />
                    <sm xmlns='urn:xmpp:sm:3' />
                </stream:features>
            </stream:stream>            

开启压缩

            
    //客户端请求开启压缩传输
    SENT (0):
        <compress xmlns='http://jabber.org/protocol/compress'><method>zlib</method></compress>
    //服务器同意开启
    RECV (0):
        <compressed xmlns='http://jabber.org/protocol/compress'/>

握手

    
    //客户端发起再次请求
    SENT (0):
        <stream:stream xmlns='jabber:client' to='127.0.0.1' xmlns:stream='http://etherx.jabber.org/streams' version='1.0' id='196jv2n3s5' xml:lang='en'>
    //服务器回应
    RECV (0):
        <?xml version='1.0' encoding='utf-8'?>
        <stream:stream xmlns:stream="http://etherx.jabber.org/streams" xmlns="jabber:client" from="127.0.0.1" id="196jv2n3s5" xml:lang="en" version="1.0">
                <stream:features>
                    <mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl">
                        <mechanism>PLAIN</mechanism>
                        <mechanism>SCRAM-SHA-1</mechanism>
                        <mechanism>CRAM-MD5</mechanism>
                        <mechanism>DIGEST-MD5</mechanism>
                    </mechanisms>
                    <ver xmlns="urn:xmpp:features:rosterver" />
                    <bind xmlns="urn:ietf:params:xml:ns:xmpp-bind" />
                    <session xmlns="urn:ietf:params:xml:ns:xmpp-session">
                        <optional />
                    </session>
                    <sm xmlns='urn:xmpp:sm:2' />
                    <sm xmlns='urn:xmpp:sm:3' />
                </stream:features>
            </stream:stream>
            
            
    //资源绑定
    SENT (0):
        <iq id='rhrxe-3' type='set'><bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><resource>wzh</resource></bind></iq>
    //服务器资源绑定成功
    RECV (0):
        <iq type="result" id="rhrxe-3" to="127.0.0.1/196jv2n3s5"><bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"><jid>wzh@127.0.0.1/wzh</jid></bind></iq>
        
        
    //请求开启流服务器(XEP-0198),需要4.0以后的openfire服务器才支持
    SENT (0):
        <enable xmlns='urn:xmpp:sm:3' resume='true'/>
    //服务器支持该协议的话,开启流服务器
    RECV (0):
        <enabled xmlns="urn:xmpp:sm:3" resume="true" id="d3poADE5Nmp2Mm4zczU="/>

接下来采用SCRAM-SHA-1机制,如果不对SASL进行配置的话,这是默认被采用的机制,下面是登录报文

    //默认步骤,请求连接服务器
    SENT (0): 
        <stream:stream xmlns='jabber:client' to='127.0.0.1' xmlns:stream='http://etherx.jabber.org/streams' version='1.0' xml:lang='en'>
    //服务器接收到请求,告诉客户端你的id
    RECV (0): 
        <?xml version='1.0' encoding='utf-8'?>
        <stream:stream xmlns:stream="http://etherx.jabber.org/streams" xmlns="jabber:client" from="127.0.0.1" id="3fvx965utw" xml:lang="en" version="1.0"></stream:stream>
    //鉴权验证阶段,在mechanisms标签中,告知客户端openfire服务器支持多少种mechanism,由客户端自行选择适合的mechanism进行鉴权操作
    //compression标签告知客户端,服务器的压缩方法,
    RECV (0): 
        <?xml version="1.0"?>
        <stream:features>
            <starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"></starttls>
            <mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl">
                <mechanism>PLAIN</mechanism>
                <mechanism>SCRAM-SHA-1</mechanism>
                <mechanism>CRAM-MD5</mechanism>
                <mechanism>DIGEST-MD5</mechanism>
            </mechanisms>
            <compression xmlns="http://jabber.org/features/compress">
                <method>zlib</method>
            </compression>
            <ver xmlns="urn:xmpp:features:rosterver" />
            <register xmlns="http://jabber.org/features/iq-register" />
        </stream:features>

鉴权过程

        
    //challenge-response校验过程,关于程序的实现可以从XMPPTCPConnection的login过程去查看具体实现
    //客户端选用SCRAM-SHA-1机制,发送初始的字符串,由ScramMechanism.getAuthenticationText()方法生成,也可以是null
    SENT (0): 
        <auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='SCRAM-SHA-1'>biwsbj13emgscj0wP2subiQzXyQ4MF9EUjRjPydAYmouSGh5ZVsvM1BIeg==</auth>
    //服务器返回一个challenge,俗称挑战码,如果客户端挑战成功的话,登录成功。需要注意的是,如果在这里SASL验证失败,这个连接不能重新验证,需要重新builder一个连接再次登录
    RECV (0): 
        <challenge xmlns="urn:ietf:params:xml:ns:xmpp-sasl">cj0wP2subiQzXyQ4MF9EUjRjPydAYmouSGh5ZVsvM1BIemEwNWM4ZWMwLWUxN2YtNGMzYS05NDVkLWZjMWUxNTNlYTNmYixzPW1Ha3pxNTk3QkdGSU5RYU1mc2xCUGdKUzkxWDlVSWVHLGk9NDA5Ng==</challenge>
    SENT (0): 
        <response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>Yz1iaXdzLHI9MD9rLm4kM18kODBfRFI0Yz8nQGJqLkhoeWVbLzNQSHphMDVjOGVjMC1lMTdmLTRjM2EtOTQ1ZC1mYzFlMTUzZWEzZmIscD1rSGhBMXZKYVJiMmowTFZ3R01ibkN4NnFqWFk9</response>
    RECV (0): 
        <success xmlns="urn:ietf:params:xml:ns:xmpp-sasl">dj0wQW9qeG5kMXhHWFNYbTVVSlhLeHBMTUFyczA9</success>
        

握手及其他连接

    //握手    
    SENT (0): 
        <stream:stream xmlns='jabber:client' to='127.0.0.1' xmlns:stream='http://etherx.jabber.org/streams' version='1.0' id='3fvx965utw' xml:lang='en'>
    RECV (0): 
        <?xml version='1.0' encoding='utf-8'?>
        <stream:stream xmlns:stream="http://etherx.jabber.org/streams" xmlns="jabber:client" from="127.0.0.1" id="3fvx965utw" xml:lang="en" version="1.0">
            <stream:features>
                <compression xmlns="http://jabber.org/features/compress">
                    <method>zlib</method>
                </compression>
                <ver xmlns="urn:xmpp:features:rosterver" />
                <bind xmlns="urn:ietf:params:xml:ns:xmpp-bind" />
                <session xmlns="urn:ietf:params:xml:ns:xmpp-session">
                    <optional />
                </session>
                <sm xmlns='urn:xmpp:sm:2' />
                <sm xmlns='urn:xmpp:sm:3' />
            </stream:features>
        </stream:stream>
        
        
    //开启压缩
    SENT (0): 
        <compress xmlns='http://jabber.org/protocol/compress'><method>zlib</method></compress>
    RECV (0): 
        <compressed xmlns='http://jabber.org/protocol/compress'/>
        
    //握手
    SENT (0): 
        <stream:stream xmlns='jabber:client' to='127.0.0.1' xmlns:stream='http://etherx.jabber.org/streams' version='1.0' id='3fvx965utw' xml:lang='en'>
    RECV (0): 
        <?xml version='1.0' encoding='utf-8'?>
        <stream:stream xmlns:stream="http://etherx.jabber.org/streams" xmlns="jabber:client" from="127.0.0.1" id="3fvx965utw" xml:lang="en" version="1.0">
            <stream:features>
                <mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl">
                    <mechanism>PLAIN</mechanism>
                    <mechanism>SCRAM-SHA-1</mechanism>
                    <mechanism>CRAM-MD5</mechanism>
                    <mechanism>DIGEST-MD5</mechanism>
                </mechanisms>
                <ver xmlns="urn:xmpp:features:rosterver" />
                <bind xmlns="urn:ietf:params:xml:ns:xmpp-bind" />
                <session xmlns="urn:ietf:params:xml:ns:xmpp-session">
                    <optional />
                </session>
                <sm xmlns='urn:xmpp:sm:2' />
                <sm xmlns='urn:xmpp:sm:3' />
            </stream:features>
        </stream:stream>
        
    //绑定资源
    SENT (0): 
        <iq id='GJh2Y-3' type='set'><bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><resource>wzh</resource></bind></iq>
    RECV (0): 
        <iq type="result" id="GJh2Y-3" to="127.0.0.1/3fvx965utw"><bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"><jid>wzh@127.0.0.1/wzh</jid></bind></iq>
        
    //开启流服务
    SENT (0): 
        <enable xmlns='urn:xmpp:sm:3' resume='true'/>
    RECV (0): 
        <enabled xmlns="urn:xmpp:sm:3" resume="true" id="d3poADNmdng5NjV1dHc="/>

以上是对客户端连接openfire服务器登录报文的初步学习,关于使用TLS连接会在下篇文章中写出。

相关文章

  • XMPP通讯安全--SASL协议学习

    在使用smack开发聊天功能的时候,对XMPP协议中使用TLS和SSAL协议保证通讯安全的知识进行学习和记录。文章...

  • XMPP (小明屁屁?) 麦盖鬼?

    一. 麦盖系XMPP? 1.XMPP (可扩展通讯和表示协议) 2.XMPP是一个机遇XML的及时通讯协议, 官方...

  • XMPP与环信

    XMPP --> 环信1.XMPP是网络层基于TCP协议,数据层基于XML协议的即时通讯协议。所以要实现通讯的话,...

  • 02-即时通讯-XMPP 简单介绍

    XMPP是什莫 1.XMPP:可扩展通讯和表示协议 2.XMPP是一种基于XML的即时通讯 3.XMPP的官方文档...

  • A Simply IM Prototype

    即时通讯也就是 IM,QQ,微信等的总称。即时通讯协议有XMPP,MQTT等。XMPP协议在 IM 上生态较为完善...

  • iOS开发之-XMPP协议及时通讯

    刚好最近在做一个项目,里面有用到XMPP通讯协议,其实相较于其他通讯协议,XMPP比较厚重,不适合以即时通讯为主的...

  • XMPP - 协议简介

    要学习基于XMPP协议的IM开发,首先要熟悉XMPP协议本身。 XMPP协议的组成主要的XMPP 协议范本及当今应...

  • XMPP(IPTV项目消息通讯)

    【XMPP】可扩展通讯和表示协议, Extensible Messaging and Presence Proto...

  • XMPP面试问题-1

    有没有做过即时通讯?是否使用过XMPP,讲述一下XMPP的实现原理 XMPP是一个即时通讯的协议,它规范了用于即时...

  • 2018-07-26

    Android即时通讯四种协议之一 XMPP协议 1.Android即时通讯是什么? 大多数及时通讯协议已经超过了...

网友评论

      本文标题:XMPP通讯安全--SASL协议学习

      本文链接:https://www.haomeiwen.com/subject/qewtnftx.html