天天看點

ssh協定原理以及實作

ssh(Secure SHell)的誕生:

    網際網路最初的時候,人們使用telnet遠端登陸主機進行操作,但是telnet協定用緻命缺陷,它的認證過程和資料傳輸過程都是明文的,這樣,我們主機的資訊很容易被他人竊取,于是人們發明ssh協定來解決這個問題。

ssh原理:(摘抄自http://bbs.hh010.com/thread-140062-1-1.html,别問我為什麼不自己寫,一個字,懶)

ssh支援多種認證方式,比較常見的有兩種:基于密碼的方式和基于主機密鑰的方式。

    大概過程如下(假設從A連接配接到B,基于密碼方式):

        1.主機A向主機B發起會話請求

        2.主機B向主機A發送主機認證資訊(主機公鑰等,主機的身份隻能自己确認,這也是為什麼我們第一次用ssh連接配接遠端主機的時候,會有提示問我們是否接受主機指紋資訊,接受後,這些資訊儲存在目前登陸使用者家目錄的.ssh/known_hosts裡面)

<a href="http://s5.51cto.com/wyfs02/M02/8A/3F/wKiom1gr2FOAiwPQAAAmHTizsm8308.png-wh_500x0-wm_3-wmp_4-s_359115347.png" target="_blank"></a>

        3.主機A确認後,生成随機對稱密鑰,并用主機B發來的公鑰加密,然後開始加密進行主機B上的系統使用者認證(這個使用者認證跟主機認證是兩回事)

        4.主機B通過主機A的認證資訊後,兩者建立長久連接配接,開始正常的安全通信

基于主機密鑰方式需要事先傳遞主機A的主機密鑰到主機B(即所謂的免密碼登陸),大概過程如下:

    1.主機A生成一對密鑰

        ssh-keygen -t rsa -f .ssh/id_rsa (預設自己會額外生成.ssh/id_rsa.pub(公鑰是從密鑰中提取的))

            -t:指定加密算法,一般兩種rsa和dsa,優先rsa

            -f:指定輸出位置,不選的話預設.ssh/id_rsa,可以選擇其他自定義路徑和名字,但是需要修改/etc/ssh/ssh_config裡面的IdentityFile參數,且必須目前登陸使用者可以通路自定義目錄,否則無法進行主機免密碼登陸操作

            -N:輸入對生成的私鑰的加密密碼,''為不加密,結合這個參數可在腳本中生成主機密鑰對

    2.主機A把生成的公鑰導入到主機B使用者家目錄下的.ssh/authorized_keys

        ssh-copy-id  -i .ssh/id_rsa.pub [root@]x.x.x.x 

            -i:要拷貝的公鑰,預設.ssh/id_rsa.pub,自定義話就根據自定義的路徑

            root@:之是以加方框是因為它可以省略,省略的話預設以目前登陸使用者的身份傳遞,拷貝到主機B對應使用者的家目錄下的.ssh/authorized_keys,當然這個使用者必須對方主機上有,否則會認證失敗,也可以自己指定

     3.以後當有新的會話請求過來的時候,主機B先檢視對應使用者家目錄下的.ssh/authorized_keys是否有相對應資訊,有的話就直接利用主機公鑰傳送資訊,主機A收到後用私鑰解密,進而進行安全通信,否則,主機B繼續按基于密碼方式進行通信

在整個通訊過程中,為實作SSH的安全連接配接,伺服器端與用戶端要經曆如下五個階段

1:版本協商階段

具體步驟如下:

    (1)伺服器打開端口22,等待用戶端連接配接。

    (2)用戶端向伺服器端發起TCP初始連接配接請求。

    (3)TCP連接配接建立後,伺服器向用戶端發送第一個封包,包括版本标志字元串,格式為“SSH-&lt;主協定版本号&gt;.&lt;次協定版本号&gt;-&lt;軟體版本号&gt;”,協定版本号由主版本号和次版本号組成,軟體版本号主要是為調試使用。

    (4)用戶端收到封包後,首先解析該資料包,通過與伺服器端的協定版本号進行對比,決定要使用的協定版本号。如果伺服器端的協定版本号比自己的低,且用戶端能支援伺服器端的低版本,就使用伺服器端的低版本協定号,否則使用自己的協定版本号。然後,用戶端回應伺服器一個封包,包含了用戶端決定使用的協定版本号。

    (5)伺服器比較用戶端發來的版本号,如果伺服器支援該版本,則使用該版本,并進入密鑰和算法協商階段,否則,版本協商失敗,伺服器端斷開TCP連接配接。

2.密鑰和算法協商階段

    (1)伺服器端和用戶端分别發送算法協商封包給對端,封包中包含自己支援的公鑰算法清單、加密算法清單、MAC(Message Authentication Code,消息驗證碼)算法清單、壓縮算法清單等。

    (2)伺服器端和用戶端根據對端和本端支援的算法清單得出最終使用的算法。任何一種算法協商失敗,都會導緻伺服器端和用戶端的算法協商過程失敗,伺服器将斷開與用戶端的連接配接。

    (3)伺服器端和用戶端利用DH交換(Diffie-Hellman Exchange)算法、主機密鑰對等參數,生成會話密鑰和會話ID,并完成用戶端對伺服器身份的驗證。

通過以上步驟,伺服器端和用戶端就取得了相同的會話密鑰和會話ID。對于後續傳輸的資料,兩端都會使用會話密鑰進行加密和解密,保證了資料傳送的安全。會話ID用來辨別一個SSH連接配接,在認證階段,會話ID還會用于兩端的認證過程。

3.認證階段

SSH提供兩種認證方法:

    (1).password認證:利用AAA(Authentication、Authorization、Accounting,認證、授權和計費)對用戶端身份進行認證。用戶端向伺服器發出password認證請求,将使用者名和密碼加密後發送給伺服器;伺服器将該資訊解密後得到使用者名和密碼的明文,通過本地認證或遠端認證驗證使用者名和密碼的合法性,并傳回認證成功或失敗的消息。如果遠端認證伺服器要求使用者進行二次密碼認證,則會在發送給伺服器端的認證回應消息中攜帶一個提示資訊,該提示資訊被伺服器端透傳給用戶端,由用戶端輸出并要求使用者再次輸入一個指定類型的密碼,當使用者送出正确的密碼并成功通過認證伺服器的驗證後,伺服器端才會傳回認證成功的消息。

    (2).publickey認證:采用數字簽名的方法來認證用戶端。目前,裝置上可以利用RSA和DSA兩種公鑰算法實作數字簽名。用戶端發送包含使用者名、公鑰和公鑰算法的publickey認證請求給伺服器端。伺服器對公鑰進行合法性檢查,如果不合法,則直接發送失敗消息;否則,伺服器利用數字簽名對用戶端進行認證,并傳回認證成功或失敗的消息。

    對于SSH2,除了上述兩種認證方法外,還提供了password-publickey認證和any認證:

    (3).password-publickey認證:指定用戶端版本為SSH2的使用者認證方式為必須同時進行password和publickey兩種認證;用戶端版本為SSH1的使用者認證方式為隻要進行其中一種認證即可。

    (4).any認證:不指定使用者的認證方式,使用者既可以采用password認證,也可以采用publickey認證。

認證階段的具體步驟如下:

    (1).用戶端向伺服器端發送認證請求,認證請求中包含使用者名、認證方法(password認證或publickey認證)、與該認證方法相關的内容(如:password認證時,内容為密碼)。

    (2).伺服器端對用戶端進行認證,如果認證失敗,則向用戶端發送認證失敗消息,其中包含可以再次認證的方法清單。

    (3).用戶端從認證方法清單中選取一種認證方法再次進行認證。

    該過程反複進行,直到認證成功或者認證次數達到上限,伺服器關閉連接配接為止。

4.會話請求階段

    認證通過後,用戶端向伺服器發送會話請求。伺服器等待并處理用戶端的請求。在這個階段,請求被成功處理後,伺服器會向用戶端回應SSH_SMSG_SUCCESS包,SSH進入互動會話階段;否則回應SSH_SMSG_FAILURE包,表示伺服器處理請求失敗或者不能識别請求。

5.互動會話階段

    會話請求成功後,連接配接進入互動會話階段。在這個階段,資料被雙向傳送。用戶端将要執行的指令加密後傳給伺服器,伺服器接收到封包,解密後執行該指令,将執行的結果加密發還給用戶端,用戶端将接收到的結果解密後顯示到終端上。

ssh的實作:openssh

用戶端:

    linux:openssh-clients包,配置檔案:/etc/ssh/ssh_config,主要有ssh、scp、sftp指令

        ssh指令:

            ssh  [user@]hostname [command]

            -l:指定登陸使用者

            -p:指定端口

            [command]:加上這個可以遠端執行指令,并傳回執行結果,一般用''引起來

            -X:允許X11轉發(我知道這翻譯不好,求大神指點..)

        scp指令:類似于cp,很多參數通用

            scp [[user@]host1:]file1 ... [[user@]host2:]file2

            -r:遞歸複制,複制目錄時有用

            -p:複制時保留檔案的時間屬性(atime、mtime)和權限

            -P:指定端口

            sftp指令:跟普通ftp指令用法一樣,差别在于它是基于ssh的,我們可以在sshd的配置檔案sshd_config中看到Subsystemsftp/usr/libexec/openssh/sftp-server這行,是以預設sshd開啟的時候,它也會維持一個sftp服務

    windows:Xmanager,SecureCRT,putty等

服務端:

    windows:我也不知道有沒有..

    linux:sshd 配置檔案:/etc/ssh/sshd_config

sshd_config:部分參數解釋:

<code>#Port 22   //指定監聽端口</code>

<code>#AddressFamily any</code>

<code>#ListenAddress 0.0.0.0</code>

<code>#ListenAddress ::</code>

<code># Disable legacy (protocol version 1) support in the server for new</code>

<code># installations. In future the default will change to require explicit</code>

<code># activation of protocol 1</code>

<code>Protocol 2 </code><code>//</code><code>指定協定版本,</code><code>ssh</code><code>有sshv1和sshv2兩個版本,sshv1不安全,是以已經棄用</code>

<code># HostKey for protocol version 1</code>

<code>#HostKey /etc/ssh/ssh_host_key     //指定使用不同版本ssh協定和不同加密算法時,向用戶端傳送的主機密鑰</code>

<code># HostKeys for protocol version 2</code>

<code>#HostKey /etc/ssh/ssh_host_rsa_key</code>

<code>#HostKey /etc/ssh/ssh_host_dsa_key</code>

<code># Lifetime and size of ephemeral version 1 server key</code>

<code>#KeyRegenerationInterval 1h        //指定對稱密鑰更新時間間隔,我們知道資料傳輸有可能被截取暴力破解,這個參數有助于安全</code>

<code>#ServerKeyBits 1024        //指定對稱密鑰位數</code>

<code># Logging</code>

<code># obsoletes QuietMode and FascistLogging</code>

<code>#SyslogFacility AUTH   //使用syslog AUTH子系統</code>

<code>SyslogFacility AUTHPRIV</code>

<code>#LogLevel INFO         //通知級别</code>

<code># Authentication:</code>

<code>#LoginGraceTime 2m     //指定等待使用者輸入的時間,超過這個時間就斷開</code>

<code>#PermitRootLogin yes   //是否允許root直接登入,(可以先登入後su),這是因為我們ssh通信進行主機認證後,如果是基于密碼的方式,一般接下來就是進行使用者認證,這個時候有可能被人截取資料封包進行暴力破解,而root是linux中的最高權限,是以這是很危險的,最好是不允許</code>

<code>#StrictModes yes</code>

<code>#MaxAuthTries 6</code>

<code>#MaxSessions 10</code>

<code>#RSAAuthentication yes</code>

<code>#PubkeyAuthentication yes</code>

<code>#AuthorizedKeysFile .ssh/authorized_keys    //已經認證的主機密鑰檔案位置,可以自定義,增加安全性</code>

<code>#AuthorizedKeysCommand none</code>

<code>#AuthorizedKeysCommandRunAs nobody</code>

<code># For this to work you will also need host keys in /etc/ssh/ssh_known_hosts</code>

<code>#RhostsRSAAuthentication no</code>

<code># similar for protocol version 2</code>

<code>#HostbasedAuthentication no</code>

<code># Change to yes if you don't trust ~/.ssh/known_hosts for</code>

<code># RhostsRSAAuthentication and HostbasedAuthentication</code>

<code>#IgnoreUserKnownHosts no</code>

<code># Don't read the user's ~/.rhosts and ~/.shosts files</code>

<code>#IgnoreRhosts yes</code>

<code># To disable tunneled clear text passwords, change to no here!</code>

<code>#PasswordAuthentication yes</code>

<code>#PermitEmptyPasswords no</code>

<code>PasswordAuthentication </code><code>yes</code>

<code># Change to no to disable s/key passwords</code>

<code>#ChallengeResponseAuthentication yes</code>

<code>ChallengeResponseAuthentication no</code>

<code># Kerberos options</code>

<code>#KerberosAuthentication no</code>

<code>#KerberosOrLocalPasswd yes</code>

<code>#KerberosTicketCleanup yes</code>

<code>#KerberosGetAFSToken no</code>

<code>#KerberosUseKuserok yes</code>

<code># GSSAPI options</code>

<code>#GSSAPIAuthentication no</code>

<code>GSSAPIAuthentication </code><code>yes</code>

<code>#GSSAPICleanupCredentials yes</code>

<code>GSSAPICleanupCredentials </code><code>yes</code>

<code>#GSSAPIStrictAcceptorCheck yes</code>

<code>#GSSAPIKeyExchange no</code>

<code># Set this to 'yes' to enable PAM authentication, account processing, </code>

<code># and session processing. If this is enabled, PAM authentication will </code>

<code># be allowed through the ChallengeResponseAuthentication and</code>

<code># PasswordAuthentication.  Depending on your PAM configuration,</code>

<code># PAM authentication via ChallengeResponseAuthentication may bypass</code>

<code># the setting of "PermitRootLogin without-password".</code>

<code># If you just want the PAM account and session checks to run without</code>

<code># PAM authentication, then enable this but set PasswordAuthentication</code>

<code># and ChallengeResponseAuthentication to 'no'.</code>

<code>#UsePAM no</code>

<code>UsePAM </code><code>yes</code>

<code># Accept locale-related environment variables</code>

<code>AcceptEnv LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES</code>

<code>AcceptEnv LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT</code>

<code>AcceptEnv LC_IDENTIFICATION LC_ALL LANGUAGE</code>

<code>AcceptEnv XMODIFIERS</code>

<code>#AllowAgentForwarding yes</code>

<code>#AllowTcpForwarding yes</code>

<code>#GatewayPorts no</code>

<code>#X11Forwarding no</code>

<code>X11Forwarding </code><code>yes</code>

<code>#X11DisplayOffset 10</code>

<code>#X11UseLocalhost yes</code>

<code>#PrintMotd yes</code>

<code>#PrintLastLog yes</code>

<code>#TCPKeepAlive yes</code>

<code>#UseLogin no</code>

<code>#UsePrivilegeSeparation yes</code>

<code>#PermitUserEnvironment no</code>

<code>#Compression delayed</code>

<code>#ClientAliveInterval 0</code>

<code>#ClientAliveCountMax 3</code>

<code>#ShowPatchLevel no</code>

<code>#UseDNS yes</code>

<code>#PidFile /var/run/sshd.pid</code>

<code>#MaxStartups 10:30:100</code>

<code>#PermitTunnel no</code>

<code>#ChrootDirectory none</code>

<code># no default banner path</code>

<code>#Banner none</code>

<code># override default of no subsystems</code>

<code>Subsystem   </code><code>sftp</code>    <code>/usr/libexec/openssh/sftp-server</code>

<code># Example of overriding settings on a per-user basis</code>

<code>#Match User anoncvs</code>

<code>#   X11Forwarding no</code>

<code>#   AllowTcpForwarding no</code>

<code>#   ForceCommand cvs server</code>

本文轉自biao007h51CTO部落格,原文連結:http://blog.51cto.com/linzb/1873389 ,如需轉載請自行聯系原作者

繼續閱讀