衆所周知ssh是目前較可靠,專爲遠程登陸會話和其餘網絡服務提供安全性的協議,它默認工做在tcp的22號端口,具體實現的軟件有:openssh(centos默認安裝的),dropbear。ssh協議目前有兩個版本v1和v2,v1基於CRC-32作MAC,不安全。v2基於DH算法作密鑰交換,基於RSA或DSA實現身份認證。因此目前大多流行的Linux都是使用的V2版本。算法
簡單瞭解了下ssh,咱們再來講說它的兩種用戶登陸認證方式,第一種基於用戶名口令的方式,這種認證方式想必你們都應該知道,就是咱們要想登陸遠端Linux系統,咱們必需要輸入相應的用戶名口令才能夠登陸到遠程Linux系統,這種方式是交互式方式登陸。第二種就是咱們今天要說的基於key的認證方式。docker
首先咱們來了解下ssh加密通信的過程centos
從上圖能夠看到,客戶端上必須存在一對密鑰對,咱們都知道密鑰是成對出現,何況用A的公鑰加密只有A的私鑰才能夠解密。正是由於非對稱加密的這個特性,咱們不難理解ssh通訊也是利用這個特性來肯定數據安全的。在服務端也有一對公鑰和私鑰,它存在的目的也是爲了加密和解密數據。ssh加密通信的流程大體上這樣的,客戶端要和服務端加密通訊,首先客戶端須要拿到服務端的公鑰,拿到服務端的公鑰後,就能夠用服務端的公鑰對要發送到數據加密,而後發送到服務端,服務端收到這個密文的數據,它會用本身的私鑰去解密,從而實現了客戶端到服務端的數據加密。同理服務端要把數據發送給客戶端也是同樣的過程,拿到客戶端的公鑰用客戶端的公鑰加密,而後發給客戶端,客戶端用本身的私鑰解密,從而實現了你來我往的加密通信。安全
咱們想一下,服務端和客戶端通信都是用對方的公鑰來加密數據,那麼客戶端是怎麼拿到服務端的公鑰的呢?服務端又是怎麼樣拿到客戶端的公鑰的呢?bash
來看一下服務端和客戶端在第一次鏈接的時候,公鑰交換的過程服務器
首先客戶端向服務端發送ssh鏈接請求,服務端收到請求後,會把本身的公鑰和會話ID 一併發送給客戶端,客戶端收到服務器發來的公鑰後,它又把本身的公鑰和服務器發送過來的會話ID 作異或運算,把獲得的結果用服務端的公鑰來加密,而後把加密後的密文經過網絡發送給服務端,服務端收到客戶端發送過來的密文後,它會用本身的私鑰去解密,而後把獲得的結果和以前的會話ID作異或計算,最終獲得客戶端的公鑰。這樣的一個過程後,客戶端就擁有了服務端的公鑰,服務端也擁有了客戶端的公鑰,有了對方的公鑰後,後續就能夠用對方的公鑰來加密數據。網絡
使用過Linux的人都知道,在咱們第一次和服務器創建ssh遠程鏈接的時候,會有一個確認,問咱們是否繼續鏈接,咱們輸入yes後才能輸入密碼,這是我爲何呢?其實在服務端發送本身的公鑰到客戶端的時候,由於客戶端沒有辦法確認它收到的公鑰是否是對方服務器發送過來的,它就會把收到的公鑰作md5和sha256,提取出公鑰的指紋,而後提示咱們說我收到了一份md5爲xxx的公鑰,請問你確認這個公鑰嗎?若是咱們確認,就表示相信這個公鑰是服務器發送過來的,這樣一來才能夠有下面的,把本身的公鑰和會話ID作異或運算,把結果用剛纔收到的公鑰加密。咱們想象,若是不是服務器發過來的公鑰,而是黑客發送過來的公鑰,若是咱們確認了,後續的密文黑客拿到後,黑客就以用本身的私鑰來解密,獲得客戶端的公鑰和數據,而後他獲得真正的數據後,黑客能夠任意改動,而後再用服務器的公鑰加密,發送給服務端,這樣一來服務端獲得的數據就是黑客修改後的數據,不是真正客戶端發送的數據。這就是所謂的中間人攻擊,它是利用本身的公鑰來回冒充服務端和客戶端角色。併發
瞭解了ssh加密通信的過程和密鑰交換的過程,咱們再來看看,ssh基於用戶名口令和密鑰登陸驗證的過程。dom
基於用戶名口令登陸是這樣的流程:首先客戶端發起ssh鏈接請求,服務端會把本身的公鑰發送給客戶端,客戶端收到服務端的公鑰後,把密碼通過服務端的公鑰加密後發送給服務端,服務端收到加密後的密碼用本身的私鑰進行解密,獲得客戶端發送過來的密碼,而後它會拿這個密碼進行驗證,把驗證的的結果用客戶端的公鑰加密併發送給客戶端,客戶端收到結果後,用本身的私鑰解密,從而實現了驗證過程,若是驗證經過,那麼客戶端就登陸成功,反之客戶端登陸失敗。ssh
基於密鑰登陸驗證的過程是:首先客戶端要生成一對密鑰對(這個密鑰對是針對的是用戶,不是主機的公鑰私鑰,前面說到的都是主機的公鑰和私鑰),並手動的將生成的公鑰添加到服務器(默認添加到服務器的某個用戶家目錄的.ssh/authorized_keys,咱們要用那個用戶鏈接服務器,就把公鑰添加到那個用戶的家目錄的.ssh/authorized_keys文件中去),服務端有了客戶端用戶的公鑰後,在客戶端發起ssh鏈接請求的時候,服務端會生成一串隨機字符,用相應的客戶端用戶的公鑰加密此隨機字符串,而後發送給客戶端,客戶端收到了服務端發送過來的加密的隨機字符後,客戶端就會用本身的私鑰來解密,而後把解密後的隨機字符發送給服務端,服務端收到客戶端發送過來的隨機字符後,它就會進行對比,若是和以前發送的隨機字符相同,那麼服務端就容許免密碼登陸。
經過上面的介紹,不難發現咱們要基於key驗證登陸,必需要在客戶端生成一對用戶密鑰對,而且要將生成的用戶公鑰放在服務端的某一個用戶的家目錄的.ssh/authorized_keys文件中,這個用戶就是咱們未來用於key驗證登陸服務器的用戶。接下來咱們來試驗試驗。
一、在客戶端生成用戶密鑰對
[qiuhom@docker ~]$ssh-keygen -t rsa Generating public/private rsa key pair. Enter file in which to save the key (/home/qiuhom/.ssh/id_rsa): Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /home/qiuhom/.ssh/id_rsa. Your public key has been saved in /home/qiuhom/.ssh/id_rsa.pub. The key fingerprint is: SHA256:CbICoBfN3670ucEBjhDR/ltyYoe/jJMIWCkCK5Lt5eA qiuhom@docker The key's randomart image is: +---[RSA 2048]----+ |. += | |+ o+ | |++oo..o. | |Bo=.o=.o.. | |+*.+o..oS | |. E.. B.=. | | . + %o. | | . =o+. | | ..+o | +----[SHA256]-----+ [qiuhom@docker ~]$ll .ssh/ 總用量 8 -rw------- 1 qiuhom qiuhom 1675 11月 2 16:54 id_rsa -rw-r--r-- 1 qiuhom qiuhom 395 11月 2 16:54 id_rsa.pub [qiuhom@docker ~]$
說明:在Linux裏咱們用ssh-keygen命令來生成用戶密鑰對,-t 選項表示以那種加密算法來生產密鑰。生成好的密鑰對,默認放在當前用戶的家目錄下.ssh/目錄下,分別叫id_rsa 和id_rsa.pub,從名字上咱們就能夠知道id_rsa是私鑰id_rsa.pub是公鑰。心細的你必定看到,咱們用ssh-keygen來生成密鑰,它會問咱們須要把密鑰文件存放在什麼地方默認是當前用戶的家目錄下的.ssh目錄下,固然咱們也能夠用-f選項來指定存放的位置,除此以外它還讓咱們輸入密碼,這裏的密碼錶示加密私鑰的密碼,咱們都知道拿到對方的私鑰是很危險,因此係統默認會提示咱們,若是按回車就表示生成的私鑰不加密,固然咱們也能夠用 -P(大寫)選項來指定加密私鑰的密碼。
2.把用戶生成的公鑰放到服務器的用戶家目錄裏的.ssh/authorized_keys,咱們能夠用scp命令放到服務端去,也能夠經過U盤拷貝過去,可是這樣太麻煩。這裏咱們用專門的工具,ssh-copy-id來把用戶公鑰文件信息拷貝到服務端對應的用戶家目錄
[qiuhom@docker ~]$ssh-copy-id -i .ssh/id_rsa.pub root@192.168.0.151 /usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: ".ssh/id_rsa.pub" The authenticity of host '192.168.0.151 (192.168.0.151)' can't be established. RSA key fingerprint is SHA256:GuKvtBmWnYyxogf1nyNvp02ccon/doAKhVdF7Qy7PvA. RSA key fingerprint is MD5:88:cf:f9:df:37:16:d7:e2:c4:99:a4:97:ab:49:f0:8e. Are you sure you want to continue connecting (yes/no)? yes /usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed /usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys root@192.168.0.151's password: Number of key(s) added: 1 Now try logging into the machine, with: "ssh 'root@192.168.0.151'" and check to make sure that only the key(s) you wanted were added. [qiuhom@docker ~]$
說明:-i選項指定公鑰文件的存放位置,默認是從當前用戶的家目錄下的.ssh/公鑰文件名稱。 由於咱們拷貝公鑰以前,服務端是沒有客戶端用戶的公鑰,因此咱們拷貝用戶公鑰的時候,還須要輸入密碼進行驗證。這裏須要說明一點,咱們上述實驗服務端的sshd服務是默認工做在22端口,若是沒有工做在默認端口須要用-p(小寫)選項來指定端口。
到此咱們就作好了ssh基於key免密碼登陸驗證。
在上面的密鑰生成和發放都是基於人工去作的,這樣一臺兩臺服務器沒有什麼問題,可是服務器多了,怎麼辦呢?若是咱們須要管理不少臺服務器,咱們這裏就須要寫腳本去完成了,如下提供本人寫的腳本,實現的功能是自動生成密鑰,並自動發送到指定的主機。
[qiuhom@docker ~]$cat ssh_keygen.sh #!/bin/bash remote_host_ip=$1 remote_host_user=$2 remote_host_port=$3 remote_host_passwd=$4 local_rsa_file=~/.ssh/id_rsa local_rsa_pub_file=~/.ssh/id_rsa.pub [ $# -ne 4 ] && echo "Usage: sh $0 RemotehostIp RemotehostUser RemotehostPort RemotehostPasswd" && exit 5 [ ! -e ${local_rsa_file} ] && ssh-keygen -t rsa -P '' -f ${local_rsa_file} >/dev/null 2>&1 expect << EOF set timeout 10 spawn ssh-copy-id -i ${local_rsa_pub_file} $remote_host_user@$remote_host_ip -p $remote_host_port expect { "(yes/no)?" {send "yes\n";exp_continue} "password: " {send "$remote_host_passwd\n"} } expect eof EOF
說明:本腳本須要本身傳遠程服務器ip ,遠程主機用戶,遠程主機ssh端口以及密碼,這個腳本實現了自動生成密鑰,併發送給指定的服務器,若須要發送到更多的服務器上,能夠另外寫腳本調用此腳本,實現批量建立和分發密鑰文件的功能。
測試:
用腳本生成密鑰文件,併發送到指定服務器上去
[qiuhom@docker ~]$ll .ssh/ 總用量 0 [qiuhom@docker ~]$ssh root@192.168.0.151 The authenticity of host '192.168.0.151 (192.168.0.151)' can't be established. RSA key fingerprint is SHA256:GuKvtBmWnYyxogf1nyNvp02ccon/doAKhVdF7Qy7PvA. RSA key fingerprint is MD5:88:cf:f9:df:37:16:d7:e2:c4:99:a4:97:ab:49:f0:8e. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added '192.168.0.151' (RSA) to the list of known hosts. root@192.168.0.151's password: [root@test ~]#ll .ssh/ 總用量 4 -rw------- 1 root root 0 11月 2 17:43 authorized_keys -rw-r--r-- 1 root root 1202 10月 31 21:25 known_hosts [root@test ~]#rm -rf .ssh/* [root@test ~]#ll .ssh/ 總用量 0 [root@test ~]#exit logout Connection to 192.168.0.151 closed. [qiuhom@docker ~]$rm -rf .ssh/* [qiuhom@docker ~]$sh ssh_keygen.sh 192.168.0.151 root 22 admin spawn ssh-copy-id -i /home/qiuhom/.ssh/id_rsa.pub root@192.168.0.151 -p 22 /usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/qiuhom/.ssh/id_rsa.pub" The authenticity of host '192.168.0.151 (192.168.0.151)' can't be established. RSA key fingerprint is SHA256:GuKvtBmWnYyxogf1nyNvp02ccon/doAKhVdF7Qy7PvA. RSA key fingerprint is MD5:88:cf:f9:df:37:16:d7:e2:c4:99:a4:97:ab:49:f0:8e. Are you sure you want to continue connecting (yes/no)? yes /usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed /usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys root@192.168.0.151's password: Number of key(s) added: 1 Now try logging into the machine, with: "ssh -p '22' 'root@192.168.0.151'" and check to make sure that only the key(s) you wanted were added. [qiuhom@docker ~]$ll .ssh/ 總用量 12 -rw------- 1 qiuhom qiuhom 1675 11月 2 17:53 id_rsa -rw-r--r-- 1 qiuhom qiuhom 395 11月 2 17:53 id_rsa.pub -rw-r--r-- 1 qiuhom qiuhom 395 11月 2 17:53 known_hosts [qiuhom@docker ~]$ssh root@192.168.0.151 [root@test ~]#ll .ssh/ 總用量 4 -rw------- 1 root root 395 11月 2 17:53 authorized_keys [root@test ~]#cat .ssh/authorized_keys ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC6yfNtYfGtwyZLKuffYgFoMZfEnKhpsp1pH3Mky1UGBsUNRGHIhNZzbtVNERWkAV/NndasfHss/vEnDSHVOXRScRfH7pPCNdVdy887WlSgshG6U5UIsQnlxlkUxf0ciVlc9VEw/IIg8eXrlOmcuezadxGc32yHB7o+zkEcg7UBYClDtjp5xqzrHyLDMd5OhGqMPJO+d+OFKqhOOYAUYsUi00aM1qNbf+KHFhYbQQj96UbWRTNQYFnqIJltvDPxqq7W5GGVl0xma6PSgGYMFNwIy9PhJJ8Lxaiaw3FjC8iCWrjzRONbnaqMPqrS8wQXs95vRDi2M0egKUuRlzFjGAGB qiuhom@docker [root@test ~]#exit logout Connection to 192.168.0.151 closed. [qiuhom@docker ~]$cat .ssh/id_rsa.pub ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC6yfNtYfGtwyZLKuffYgFoMZfEnKhpsp1pH3Mky1UGBsUNRGHIhNZzbtVNERWkAV/NndasfHss/vEnDSHVOXRScRfH7pPCNdVdy887WlSgshG6U5UIsQnlxlkUxf0ciVlc9VEw/IIg8eXrlOmcuezadxGc32yHB7o+zkEcg7UBYClDtjp5xqzrHyLDMd5OhGqMPJO+d+OFKqhOOYAUYsUi00aM1qNbf+KHFhYbQQj96UbWRTNQYFnqIJltvDPxqq7W5GGVl0xma6PSgGYMFNwIy9PhJJ8Lxaiaw3FjC8iCWrjzRONbnaqMPqrS8wQXs95vRDi2M0egKUuRlzFjGAGB qiuhom@docker [qiuhom@docker ~]$
說明:能夠看到咱們腳本沒有運行以前登陸服務器須要手動輸入密碼,咱們執行了腳本後,用戶密鑰文件建立了,而且也將用戶公鑰文件發送到相應的服務器上去了。
總結:ssh基於key驗證有以下好處
一、更加安全方便。咱們不用去記繁瑣的用戶密碼,也不擔憂密碼泄露。(咱們能夠把sshd服務配置成只容許基於KEY驗證登陸)
二、基於key驗證明現免密登陸,能夠實現遠程批量操做服務器,方便腳本編寫,使得咱們在執行遠程操做命令時就好像在本地執行命令簡單(如scp,ssh)
三、有效防止暴力猜口令的威脅。