Linux系统中SSH服务基于key认证实践的过程
  众所周知ssh是⽬前较可靠,专为远程登录会话和其他⽹络服务提供安全性的协议,它默认⼯作在tcp的22号端⼝,具体实现的软件有:openssh(centos默认安装的),dropbear。ssh协议⽬前有两个版本v1和v2,v1基于CRC-32做MAC,不安全。v2基于DH算法做密钥交换,基于RSA或DSA实现⾝份认证。所以⽬前⼤多流⾏的Linux都是使⽤的V2版本。
  简单了解了下ssh,我们再来说说它的两种⽤户登录认证⽅式,第⼀种基于⽤户名⼝令的⽅式,这种认证⽅式想必⼤家都应该知道,就是我们要想登录远端Linux系统,我们必须要输⼊相应的⽤户名⼝令才可以登录到远程Linux系统,这种⽅式是交互式⽅式登录。第⼆种就是我们今天要说的基于key的认证⽅式。红旗linux认证
  ⾸先我们来了解下ssh加密通讯的过程
  从上图可以看到,客户端上必须存在⼀对密钥对,我们都知道密钥是成对出现,况且⽤A的公钥加密只有A的私钥才可以解密。正是因为⾮对称加密的这个特性,我们不难理解ssh通信也是利⽤这个特性来确定数据安全的。在服务端也有⼀对公钥和私钥,它存在的⽬的也是为了加密和解密数据。ssh加密通讯的流程⼤致上这样的,客户端要和服务端加密通信,⾸先客户端需要拿到服务端的公钥,拿到服务端的公钥后,就可以⽤服务端的公钥对要发送到数据加密,然后发送到服务端,服务端收到这个密⽂的数据,它会⽤⾃⼰的私钥去解密,从⽽实现了客户端到服务端的数据加密。同理服务端要把数据发送给客户端也是⼀样的过程,拿到客户端的公钥⽤客户端的公钥加密,然后发给客户端,客户端⽤⾃⼰的私钥解密,从⽽实现了你来我往的加密通讯。
  我们想⼀下,服务端和客户端通讯都是⽤对⽅的公钥来加密数据,那么客户端是怎么拿到服务端的公钥的呢?服务端⼜是怎么样拿到客户端的公钥的呢?
  来看⼀下服务端和客户端在第⼀次连接的时候,公钥交换的过程
  ⾸先客户端向服务端发送ssh连接请求,服务端收到请求后,会把⾃⼰的公钥和会话ID ⼀并发送给客户端,客户端收到服务器发来的公钥后,它⼜把⾃⼰的公钥和服务器发送过来的会话ID 做异或运算,把得到的结果⽤服务端的公钥来加密,然后把加密后的密⽂通过⽹络发送给服务端,服务端收到客户端发送过来的密⽂后,它会⽤⾃⼰的私钥去解密,然后把得到的结果和之前的会话ID做异或计算,最终得到客户端的公钥。这样的⼀个过程后,客户端就拥有了服务端的公钥,服务端也拥有了客户端的公钥,有了对⽅的公钥后,后续就可以⽤对⽅的公钥来加密数据。
  使⽤过Linux的⼈都知道,在我们第⼀次和服务器建⽴ssh远程连接的时候,会有⼀个确认,问我们是否继续连接,我们输⼊yes后才能输⼊密码,这是我为什么呢?其实在服务端发送⾃⼰的公钥到客户端的时候,因为客户端没有办法确认它收到的公钥是不是对⽅服务器发送过来的,它就会把收到的公钥做md5和sha256,提取出公钥的指纹,然后提⽰我们说我收到了⼀份md5为xxx的公钥,请问你确认这个公钥吗?如果我们确认,就表⽰相信这个公钥是服务器发送过来的,这样⼀来才可以有下⾯的,把⾃⼰的公钥和会话ID做异或运算,把结果⽤刚才收到的公钥加密。我们想象,如果不是服务器发过来的公钥,⽽是⿊客发送过来的公钥,如果我们确认了,后续的密⽂⿊客拿到后,⿊客就以⽤⾃⼰的私钥来解密,得到客户端的公钥和数据,然后他得到真正的数据后,⿊客可以任意改动,然后再⽤服务器的公钥加密,发送给服务端,这样⼀来服务端得到的数据就是⿊客修改后的数据,不是真正客户端发送的数据。这就是所谓的中间⼈攻击,它是利⽤⾃⼰的公钥来回冒充服务端和客户端⾓⾊。
  了解了ssh加密通讯的过程和密钥交换的过程,我们再来看看,ssh基于⽤户名⼝令和密钥登录验证的过程。
  基于⽤户名⼝令登录是这样的流程:⾸先客户端发起ssh连接请求,服务端会把⾃⼰的公钥发送给客户端,客户端收到服务端的公钥后,把密码经过服务端的公钥加密后发送给服务端,服务端收到加密后的
密码⽤⾃⼰的私钥进⾏解密,得到客户端发送过来的密码,然后它会拿这个密码进⾏验证,把验证的的结果⽤客户端的公钥加密并发送给客户端,客户端收到结果后,⽤⾃⼰的私钥解密,从⽽实现了验证过程,如果验证通过,那么客户端就登录成功,反之客户端登录失败。
  基于密钥登录验证的过程是:⾸先客户端要⽣成⼀对密钥对(这个密钥对是针对的是⽤户,不是主机的公钥私钥,前⾯说到的都是主机的公钥和私钥),并⼿动的将⽣成的公钥添加到服务器(默认添加到服务器的某个⽤户家⽬录的.ssh/authorized_keys,我们要⽤那个⽤户连接服务器,就把公钥添加到那个⽤户的家⽬录的.ssh/authorized_keys⽂件中去),服务端有了客户端⽤户的公钥后,在客户端发起ssh连接请求的时候,服务端会⽣成⼀串随机字符,⽤相应的客户端⽤户的公钥加密此随机字符串,然后发送给客户端,客户端收到了服务端发送过来的加密的随机字符后,客户端就会⽤⾃⼰的私钥来解密,然后把解密后的随机字符发送给服务端,服务端收到客户端发送过来的随机字符后,它就会进⾏对⽐,如果和之前发送的随机字符相同,那么服务端就允许免密码登录。
  通过上⾯的介绍,不难发现我们要基于key验证登录,必须要在客户端⽣成⼀对⽤户密钥对,并且要将⽣成的⽤户公钥放在服务端的某⼀个⽤户的家⽬录的.ssh/authorized_keys⽂件中,这个⽤户就是我们将来⽤于key验证登录服务器的⽤户。接下来我们来试验试验。
  1、在客户端⽣成⽤户密钥对
[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+ [root@test ~]#exit
logout
Connection to 192.168.0.151 closed.
[qiuhom@docker ~]$cat .ssh/id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC6yfNtYfGtwyZLKuffYgFoMZfEnKhpsp1pH3Mky1UGBsUNRGHIhNZzbtVNERWkAV/NndasfHss/vEnDSHVOXRScRfH7pPCNdVdy887WlSgshG6U5UIsQnlxlkUxf0ciVlc9VEw/IIg8eXrlOmcuezadxGc32yHB7o+ [qiuhom@docker ~]$
 说明:可以看到我们脚本没有运⾏之前登录服务器需要⼿动输⼊密码,我们执⾏了脚本后,⽤户密钥⽂件创建了,并且也将⽤户公钥⽂件发送到相应的服务器上去了。
总结:ssh基于key验证有如下好处
1、更加安全⽅便。我们不⽤去记繁琐的⽤户密码,也不担⼼密码泄露。(我们可以把sshd服务配置成只允许基于KEY验证登录)
2、基于key验证实现免密登录,可以实现远程批量操作服务器,⽅便脚本编写,使得我们在执⾏远程操作命令时就好像在本地执⾏命令简单(如scp,ssh)
3、有效防⽌暴⼒猜⼝令的威胁。
总结
以上所述是⼩编给⼤家介绍的Linux系统中SSH服务基于key认证实践的过程,希望对⼤家有所帮助!