zoukankan      html  css  js  c++  java
  • ssh应用层协议原理 jsch源码探究 authfail

    公司的项目需要用java实现远程登录主机,需要用的jsch jar包,但是在调用此jar包的接口的时候,总是会不经意间出现一些错误: auth faile ; 但传递的用户名和密码是正确的,这可如何是好,由于这个远程方问接口是由我维护的,所以现在这个侦查原因的重任就落在的我的身上。起初通过debug 跟踪代码发现是在创建session时抛出的异常,可是这个问题很有随机性,我在debug时就无法复现,头说让我好好研究这个ssh协议,底层实现,要知道在什么情况下才会抛出这个异常。

    一、ssh的验证方式:http://www.cnblogs.com/hukey/p/6248468.html

     有两种:(客户端指本地主机;服务端指 远程主机)

    (1) 通过密码验证

    客户端向服务器端发出连接请求; 

    服务器端将自己的公钥发送给客户端;

    客户端收到服务器端的公钥后,将服务器的用户名,密码通过公钥加密,发送给服务器端;

    服务器端用自己的秘钥来解密密码,验证密码是否正确,验证成功->允许登录;验证失败->不允许登录。

     (2)免密码登录

    客户端生成秘钥对,客户端将自己的公钥发送给服务器端,并存储在authorized_keys 文件中;

    客户端向服务器发出连接请求,传递客户端的用户名和IP等信息;

    服务器端在自己的authorized_keys文件中查找是否有此ip和用户名信息。

    若有,则随机生成一个字符串,用客户端传来的公钥对字符串进行加加密,传给客户端。

    客户端用私钥解密字符串,然后将解密后的字符串发给服务端。

    服务端用接收到的字符串和自己的字符串进行对比,若相同则允许免密码登录。


    (这样看来,ssh登录都是通过公钥加密,然后用私钥解密。不同的是:有密码登录时,客户端用服务器端的公钥来加密客户端的密码,然后传给服务器端,由服务器端来解密,验证密码能否登录;免密码登录是服务器端用客户端的公钥加密随机字符串,然后由客户端解密字符串,服务器端来验证字符串是否正确。)


    二、SSH 的工作过程  http://blog.csdn.net/macrossdzh/article/details/5691924


    http://www.jianshu.com/p/8e5b7aea52b5   这篇文章写的非常好。


    在整个通讯过程中,为实现 SSH的安全连接,服务器端与客户端要经历如下五个阶段:

        * 版本号协商阶段,SSH目前包括 SSH1和SSH2两个版本, 双方通过版本协商确定使用的版本

        * 密钥和算法协商阶段,SSH支持多种加密算法, 双方根据本端和对端支持的算法,协商出最终使用的算法

        * 认证阶段,SSH客户端向服务器端发起认证请求, 服务器端对客户端进行认证

        * 会话请求阶段, 认证通过后,客户端向服务器端发送会话请求

        * 交互会话阶段 ,会话请求通过后,服务器端和客户端进行信息的交互 

    1 . 版本号协商阶段

       1. 服务器打开端口 22,等待客户端连接。

       2. 客户端向服务器端发起 TCP初始连接请求,TCP连接建立后,服务器向客户端发送第一个报文,包括版本标志字符串,格式为“SSH-<主协议版本号>.<次协议版本号>-<软件版本号>”,协议版本号由主版本号和次版本号组成,软件版本号主要是为调试使用。

       3. 客户端收到报文后,解析该数据包,如果服务器端的协议版本号比自己的低,且客户端能支持服务器端的低版本,就使用服务器端的低版本协议号,否则使用自己的协议版本号。

       4. 客户端回应服务器一个报文,包含了客户端决定使用的协议版本号。服务器比较客户端发来的版本号,决定是否能同客户端一起工作。

       5. 如果协商成功,则进入密钥和算法协商阶段,否则服务器端断开 TCP连接。

    Note: 版本号协商阶段报文都是采用明文方式传输的。

    2. 密钥和算法协商阶段

       1. 服务器端和客户端分别发送算法协商报文给对端,报文中包含自己支持的公钥算法列表、加密算法列表、MAC(Message Authentication Code,消息验证码)算法列表、压缩算法列表等;

       2. 服务器端和客户端根据对端和本端支持的算法列表得出最终使用的算法。

       3. 服务器端和客户端利用 DH交换(Diffie-Hellman Exchange)算法、主机密钥对等参数,生成会话密钥和会话 ID。

     

          通过以上步骤,服务器端和客户端就取得了相同的会话密钥和会话ID。

              * 对于后续传输的数据,两端都会使用会话密钥进行加密和解密,保证了数据传送的安全

              * 在认证阶段,两端会使用会话 ID用于认证过程。

          Note:

                 在协商阶段之前,服务器端已经生成 RSA或 DSA密钥对,他们主要用于参与会话密钥的生成。

    3. 认证阶段

       1. 客户端向服务器端发送认证请求,认证请求中包含用户名、认证方法、与该认证方法相关的内容(如:password认证时,内容为密码)。

       2. 服务器端对客户端进行认证,如果认证失败,则向客户端发送认证失败消息,其中包含可以再次认证的方法列表。

       3. 客户端从认证方法列表中选取一种认证方法再次进行认证。

       4. 该过程反复进行, 直到认证成功或者认证次数达到上限, 服务器关闭连接为止。

     

    SSH提供两种认证方式:

       1. password认证:客户端向服务器发出 password认证请求,将用户名和密码加密后发送给服务器;服务器将该信息解密后得到用户名和密码的明文,与设备上保存的用户名和密码进行比较,并返回认证成功或失败的消息。

       2. publickey 认证:采用数字签名的方法来认证客户端。目前,设备上可以利用RSA和 DSA两种公共密钥算法实现数字签名。客户端发送包含用户名、公共密钥和公共密钥算法的 publickey 认证请求给服务器端。服务器对公钥进行合法性检查,如果不合法,则直接发送失败消息;否则,服务器利用数字签名对客户端进行认证,并返回认证成功或失败的消息

     

    SSH2.0还提供了 password-publickey 认证和 any 认证:

       1. password-publickey 认证:指定该用户的认证方式为 password 和 publickey认证同时满足。客户端版本为 SSH1的用户只要通过其中一种认证即可登录;客户端版本为 SSH2的用户必须两种认证都通过才能登录。

       2. any认证:指定该用户的认证方式可以是 password,也可以是 publickey。

     

    4.会话请求阶段

       1. 服务器等待客户端的请求;

       2. 认证通过后,客户端向服务器发送会话请求;

       3. 服务器处理客户端的请求。请求被成功处理后, 服务器会向客户端回应 SSH_SMSG_SUCCESS包,SSH进入交互会话阶段;否则回应 SSH_SMSG_FAILURE包,表示服务器处理请求失败或者不能识别请求。

     

    5.交互会话阶段

    在这个模式下,数据被双向传送:

       1. 客户端将要执行的命令加密后传给服务器;

       2. 服务器接收到报文,解密后执行该命令,将执行的结果加密发还给客户端;

       3. 客户端将接收到的结果解密后显示到终端上.

     

    三、问题

      今天拿出这个问题来,看了看这些jsch代码,还真的有些收获,最起码对原来特别陌生的代码有了一些熟悉感。

     jsch在创建session时,通过IO流getByte() 获取数据,然后将数据存储在buffer中;

    通过debug查看每个值,了解到:

    kex:   class com.jcraft.jsch.DHG14      DH交换(Diffie-Hellman Exchange)算法

    v_s:[83, 83, 72, 45, 50, 46, 48, 45, 79, 112, 101, 110, 83, 83, 72, 95, 53, 46, 51]      SSH-2.0-OpenSSH_5.3   服务端的标识字符串(CR和低频除外)

    v_c:[83, 83, 72, 45, 50, 46, 48, 45, 74, 83, 67, 72, 45, 48, 46, 49, 46, 53, 52]   SSH-2.0-JSCH-0.1.54  客户机的标识字符串(CR和低频除外)

    I_C:[20, -99, 110, -119, -78, -23, 42, -49, -32, -109, -113, -11, -98, 100, 90, -25, 2, 0, 0, 0, -73, 101, 99, 100, 104, 45, 115, 104, 97, 50, 45, 110, 105, 115, 116, 112, 50, 53, 54, 44, 101, 99, 100, 104, 45, 115, 104, 97, 50, 45, 110, 105, 115, 116, 112, 51, 56, 52, 44, 101, 99, 100, 104, 45, 115, 104, 97, 50, 45, 110, 105, 115, 116, 112, 53, 50, 49, 44, 100, 105, 102, 102, 105, 101, 45, 104, 101, 108, 108, 109, 97, 110, 45, 103, 114, 111, 117, 112, 49, 52, 45, 115, 104, 97, 49, 44, 100, 105, 102, 102, 105, 101, 45, 104, 101, 108, 108, 109, 97, 110, 45, 103, 114, 111, 117, 112, 45, 101, 120, 99, 104, 97, 110, 103, 101, 45, 115, 104, 97, 50, 53, 54, 44, 100, 105, 102, 102, 105, 101, 45, 104, 101, 108, 108, 109, 97, 110, 45, 103, 114, 111, 117, 112, 45, 101, 120, 99, 104, 97, 110, 103, 101, 45, 115, 104, 97, 49, 44, 100, 105, 102, 102, 105, 101, 45, 104, 101, 108, 108, 109, 97, 110, 45, 103, 114, 111, 117, 112, 49, 45, 115, 104, 97, 49, 0, 0, 0, 75, 115, 115, 104, 45, 114, 115, 97, 44, 115, 115, 104, 45, 100, 115, 115, 44, 101, 99, 100, 115, 97, 45, 115, 104, 97, 50, 45, 110, 105, 115, 116, 112, 50, 53, 54, 44, 101, 99, 100, 115, 97, 45, 115, 104, 97, 50, 45, 110, 105, 115, 116, 112, 51, 56, 52, 44, 101, 99, 100, 115, 97, 45, 115, 104, 97, 50, 45, 110, 105, 115, 116, 112, 53, 50, 49, 0, 0, 0, 52, 97, 101, 115, 49, 50, 56, 45, 99, 116, 114, 44, 97, 101, 115, 49, 50, 56, 45, 99, 98, 99, 44, 51, 100, 101, 115, 45, 99, 116, 114, 44, 51, 100, 101, 115, 45, 99, 98, 99, 44, 98, 108, 111, 119, 102, 105, 115, 104, 45, 99, 98, 99, 0, 0, 0, 52, 97, 101, 115, 49, 50, 56, 45, 99, 116, 114, 44, 97, 101, 115, 49, 50, 56, 45, 99, 98, 99, 44, 51, 100, 101, 115, 45, 99, 116, 114, 44, 51, 100, 101, 115, 45, 99, 98, 99, 44, 98, 108, 111, 119, 102, 105, 115, 104, 45, 99, 98, 99, 0, 0, 0, 57, 104, 109, 97, 99, 45, 109, 100, 53, 44, 104, 109, 97, 99, 45, 115, 104, 97, 49, 44, 104, 109, 97, 99, 45, 115, 104, 97, 50, 45, 50, 53, 54, 44, 104, 109, 97, 99, 45, 115, 104, 97, 49, 45, 57, 54, 44, 104, 109, 97, 99, 45, 109, 100, 53, 45, 57, 54, 0, 0, 0, 57, 104, 109, 97, 99, 45, 109, 100, 53, 44, 104, 109, 97, 99, 45, 115, 104, 97, 49, 44, 104, 109, 97, 99, 45, 115, 104, 97, 50, 45, 50, 53, 54, 44, 104, 109, 97, 99, 45, 115, 104, 97, 49, 45, 57, 54, 44, 104, 109, 97, 99, 45, 109, 100, 53, 45, 57, 54, 0, 0, 0, 4, 110, 111, 110, 101, 0, 0, 0, 4, 110, 111, 110, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]   

    ?n???*??????dZ??ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group14-sha1,diffie-hellman-group-exchange-sha256,diffie-hellman-group-exchange-sha1,diffie-hellman-group1-sha1Kssh-rsa,ssh-dss,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp5214aes128-ctr,aes128-cbc,3des-ctr,3des-cbc,blowfish-cbc4aes128-ctr,aes128-cbc,3des-ctr,3des-cbc,blowfish-cbc9hmac-md5,hmac-sha1,hmac-sha2-256,hmac-sha1-96,hmac-md5-969hmac-md5,hmac-sha1,hmac-sha2-256,hmac-sha1-96,hmac-md5-96nonenone



    https://tools.ietf.org/html/rfc4253#section-8

    8. Diffie-Hellman Key Exchange 迪菲秘钥交换

    The Diffie-Hellman (DH) key exchange provides a shared secret that cannot be determined by either party alone. The key exchange is combined with a signature with the host key to provide host authentication. This key exchange method provides explicit server authentication as defined in Section 7. The following steps are used to exchange a key. In this, C is the client; S is the server; p is a large safe prime; g is a generator for a subgroup of GF(p); q is the order of the subgroup; V_S is S's identification string; V_C is C's identification string; K_S is S's public host key; I_C is C's SSH_MSG_KEXINIT message and I_S is S's SSH_MSG_KEXINIT message that have been exchanged before this part begins. 1. C generates a random number x (1 < x < q) and computes e = g^x mod p. C sends e to S. Ylonen & Lonvick Standards Track [Page 21]

    
    RFC 4253              SSH Transport Layer Protocol          January 2006
    
    
       2. S generates a random number y (0 < y < q) and computes
          f = g^y mod p.  S receives e.  It computes K = e^y mod p,
          H = hash(V_C || V_S || I_C || I_S || K_S || e || f || K)
          (these elements are encoded according to their types; see below),
          and signature s on H with its private host key.  S sends
          (K_S || f || s) to C.  The signing operation may involve a
          second hashing operation.
    
       3. C verifies that K_S really is the host key for S (e.g., using
          certificates or a local database).  C is also allowed to accept
          the key without verification; however, doing so will render the
          protocol insecure against active attacks (but may be desirable for
          practical reasons in the short term in many environments).  C then
          computes K = f^x mod p, H = hash(V_C || V_S || I_C || I_S || K_S
          || e || f || K), and verifies the signature s on H.
    
       Values of 'e' or 'f' that are not in the range [1, p-1] MUST NOT be
       sent or accepted by either side.  If this condition is violated, the
       key exchange fails.
    
       This is implemented with the following messages.  The hash algorithm
       for computing the exchange hash is defined by the method name, and is
       called HASH.  The public key algorithm for signing is negotiated with
       the SSH_MSG_KEXINIT messages.
    
       First, the client sends the following:
    
          byte      SSH_MSG_KEXDH_INIT
          mpint     e
    
       The server then responds with the following:
    
          byte      SSH_MSG_KEXDH_REPLY
          string    server public host key and certificates (K_S)
          mpint     f
          string    signature of H
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    Ylonen &  Lonvick           Standards Track                    [Page 22]

    
    RFC 4253              SSH Transport Layer Protocol          January 2006
    
    
       The hash H is computed as the HASH hash of the concatenation of the
       following:
    
          string    V_C, the client's identification string (CR and LF
                    excluded)
          string    V_S, the server's identification string (CR and LF
                    excluded)
          string    I_C, the payload of the client's SSH_MSG_KEXINIT
          string    I_S, the payload of the server's SSH_MSG_KEXINIT
          string    K_S, the host key
          mpint     e, exchange value sent by the client
          mpint     f, exchange value sent by the server
          mpint     K, the shared secret
    
       This value is called the exchange hash, and it is used to
       authenticate the key exchange.  The exchange hash SHOULD be kept
       secret.
    
       The signature algorithm MUST be applied over H, not the original
       data.  Most signature algorithms include hashing and additional
       padding (e.g., "ssh-dss" specifies SHA-1 hashing).  In that case, the
       data is first hashed with HASH to compute H, and H is then hashed
       with SHA-1 as part of the signing operation.


    session 类中包含这些:

      Q2: 什么是HMAC?

        A2: HMAC(Hash Message Authentication Code) ,散列消息鉴别码,基于密钥的Hash算法的认证协议。消息鉴别码实现鉴别的原理是,用公开函数和密钥产生一个固定长度的值作为认证标识,用这个标识鉴别消息的完整性。使用一个密钥生成一个固定大小的小数据块,即MAC,并将其加入到消息中,然后传输。接收方利用与发送方共享的密钥进行鉴别认证等。

     


    jsch 创建session的底层源码完全是模拟的ssh通信的66步骤来实现的。首先创建socket连接;双方协商ssh协议版本;确定加密算法和公钥信息;认证阶段。




  • 相关阅读:
    CopyOnWriteArrayList源码阅读笔记
    ArrayList源码阅读笔记
    MySQL和Oracle的区别
    思维导图概览SpringCloud
    Java学习之Request篇
    Java学习之servlet篇
    Java学习之数据库连接池
    Java学习之注解篇
    Java爬取先知论坛文章
    Java学习之爬虫篇
  • 原文地址:https://www.cnblogs.com/yeemi/p/7470131.html
Copyright © 2011-2022 走看看