什么是SSH?
Secure Shell(安全外壳协议,简称SSH)是一种加密的网络传输协议,可在不安全的网络中为网络服务提供安全的传输环境[1]。SSH通过在网络中创建安全隧道来实现SSH客户端与服务器之间的连接[2]。虽然任何网络服务都可以通过SSH实现安全传输,SSH最常见的用途是远程登录系统,人们通常利用SSH来传输命令行界面和远程执行命令。使用频率最高的场合类Unix系统,但是Windows操作系统也能有限度地使用SSH。2015年,微软宣布将在未来的操作系统中提供原生SSH协议支持[3]。
在设计上,SSH是Telnet和非安全shell的替代品。Telnet和Berkeley rlogin、rsh、rexec等协议采用明文传输,使用不可靠的密码,容易遭到监听、嗅探和中间人攻击[4]。SSH旨在保证非安全网络环境(例如互联网)中信息加密完整可靠。
以上来源于维基百科。
简单来说,SSH就是一种安全协议,通常用于登陆远程服务器的加密。如果一个用户从本地计算机,使用SSH协议登录另一台远程计算机,我们就可以认为,这种登录是安全的,即使被中途截获,密码也不会泄露。如果客户端不使用SSH安全协议登陆远程服务器,密码可能被第三方(黑客)劫取,如下图。
SSH加密使用了对称加密算法和非对称加密算法。
对称加密算法
对称密钥算法(英语:Symmetric-key algorithm)又称为对称加密、私钥加密、共享密钥加密,是密码学中的一类加密算法。这类算法在加密和解密时使用相同的密钥,或是使用两个可以简单地相互推算的密钥。事实上,这组密钥成为在两个或多个成员间的共同秘密,以便维持专属的通信联系[1]。与公开密钥加密相比,要求双方获取相同的密钥是对称密钥加密的主要缺点之一[2]。
常见的对称加密算法有DES、3DES、AES、Blowfish、IDEA、RC5、RC6。
对称加密的速度比公钥加密快很多,在很多场合都需要对称加密。[3]
如图所示,客户端要给服务器发送一段信息,此处信息用
Hello!
表示。众所周知,只要是数据包,就能被他人劫取到,为了防止被别人劫取到这些信息,就需要使用秘钥将其进行加密。相应的,服务器接收到加密后的数据后需要解密,那么也就需要使用相同的秘钥进行解密。可是这样的加密方式带来一个
问题
:我们需要产生一个最初的秘钥,然后将其复制后发送给服务器,这样双方才能加密解密数据。那么,复制后的秘钥如何发送给服务器?加密后传输给服务器没有对应的秘钥就无法解密,不加密传输又可能被他人截取破解,我们想到了一个办法,非对称加密。
非对称加密算法
公开密钥密码学(英语:Public-key cryptography),也称为非对称式密码学(英语:asymmetric cryptography),是密码学的一种算法,它需要两个密钥,一个是公开密钥,另一个是私有密钥;一个用作加密,另一个则用作解密。使用其中一个密钥把明文加密后所得的密文,只能用相对应的另一个密钥才能解密得到原本的明文;甚至连最初用来加密的密钥也不能用作解密。由于加密和解密需要两个不同的密钥,故被称为非对称加密;不同于加密和解密都使用同一个密钥的对称加密。虽然两个密钥在数学上相关,但如果知道了其中一个,并不能凭此计算出另外一个[来源请求];因此其中一个可以公开,称为公钥,任意向外发布;不公开的密钥为私钥,必须由用户自行严格秘密保管,绝不透过任何途径向任何人提供,也不会透露给被信任的要通信的另一方。
如上图所示,服务器拥有公钥和私钥,它们都能加密数据,公钥加密的数据只有私钥才能解密(公钥自己无法解密),私钥加密的数据只有公钥才能解密(私钥自己无法解密)。所谓公钥,即公开的秘钥,任何人都能够获取,这里客户端获取了一把,如果黑客想要,也给他就是了。
客户端利用公钥加密数据后给服务器,服务器可以通过私钥解密,可服务器通过公钥加密数据,客户端无法解密(没有私钥)。如果服务器通过私钥加密,那么客户端可以解密,但问题是:任何人都可以获取公钥,那么私钥加密的数据任何人都能解密。
既然任何人都可以解密,那私钥加密肯定不行啊!服务器到底该如何给客户端发加密数据呢?我们在此基础上通过前面的对称加密来解决这个问题。
在客户端通过算法基于一定规则生成第三种钥匙(图中紫色钥匙),当客户端获取了公钥后,通过公钥将紫钥加密传送给服务器的私钥解密,这样服务器也得到了紫钥,解决了对称加密的问题,以后我们就能通过对称加密的方式来传输数据。也就是说,非对称加密的公钥私钥并不主要是用来传输数据(小数据会用到,但对大的数据,它们加密解密非常耗费时间,远远没有对称加密传输数据快),而是用来将紫钥从客户端复制到服务器,然后就可以通过这对紫钥进行双向加密/解密数据通信。
ssh的密码登陆
SSH之所以能够保证安全,原因在于它采用了公钥加密。
当我们使用密码登陆远程服务器,整个过程是这样的:
①当远程服务器收到某个客户端的登录请求,会准备把自己的公钥发送给客户端。
②客户端接收保存后将使用这个公钥,将输入的登录密码加密后,发送给远程服务器。
③远程服务器用自己的私钥,解密公钥加密过的登录密码,如果密码正确,就同意用户登录。
命令步骤是这样的(这里假设远程主机IP为192.168.2.128
,当然一般肯定不是这个数字):
$ ssh root@192.168.2.128
The authenticity of host '192.168.2.128 (192.168.2.128)' can't be established.
ECDSA key fingerprint is SHA256:ogcmsTImWXFIWNYpAusKfqV3GX6j/ruJy6TQ3DVoSwI.
Are you sure you want to continue connecting (yes/no)?
这段话的意思简单来说就是,你想要接收远程服务器137.36.2.1
的公钥吗?
你肯定要确定接收呀,输入yes
回车
系统会出现一句提示,表示host主机已经得到认可,并将公钥保存在文件$HOME/.ssh/known_hosts
之中。:
Warning: Permanently added '192.168.2.128' (ECDSA) to the list of known hosts.
然后,会要求输入密码。
root@192.168.2.128's password:
如果密码正确,就可以登录了。
当远程主机的公钥被接受以后,它就会被保存在文件$HOME/.ssh/known_hosts
之中。下次再连接这台主机,系统就会认出它的公钥已经保存在本地了,从而跳过警告部分,直接提示输入密码。
注:
windows用户可以使用git
工具来用ssh
命令连接远程服务器,Xshell
等工具连接远程服务器无法接受服务器的公钥。
举个例子加深理解
假设你遇到了多年不见的好友,而你的容貌有了很大的变化,好友认不出来。
好友:这SB谁啊???
于是好友想出了一个办法来证明确实认识你:
好友:给你一个打开了的保险箱(公钥),保险箱的密码(私钥)只有我知道,你拿张纸条写几个小时候的事(登录密码)放进保险箱加完锁(用公钥加密)再给我。
当好友确认后你们就能相认了。。。
大概就是这个意思,可能有人问为什么要用保险箱?emmm,你的好友可能脸盲,这样做是为了防止别人冒充你(在服务器层面来讲,就是为了防止别人窃取登录密码)。
ssh实现远程免密登录
平常我们每次登陆远程服务器都要输入密码多麻烦啊,而且远程服务器开启密码登陆可能被黑客暴力试错破解,因此后面我们会禁止服务器通过密码登录,不过我们先实现下免密登录再去那样做(不然你把密码登录关了还怎么登???哈哈):
①首先在客户端通过特定算法生成一对秘钥(公钥私钥)
ssh-keygen -t rsa -C "666666@gmail.com"
参数说明:
-t 加密算法类型,这里是使用rsa算法 如果没有指定则默认生成用于SSH-2的RSA密钥。这里使用的是rsa。
同时在密钥中有一个注释字段,用-C来指定所指定的注释,可以方便用户标识这个密钥,指出密钥的用途或其他有用的信息。
所以在这里输入自己的邮箱或者其他信息都行
当然,如果不想要这些可以直接输入(一般也是这么做的)下面命令:
ssh-keygen
之后会在用户的根目录下的.ssh
文件夹生成私钥id_rsa
和公钥id_rsa.pub
。本地的.ssh
的文件夹存在以下几个文件:
id_rsa : 执行命令后生成的私钥文件
id_rsa.pub : 执行命令后生成的公钥文件
know_hosts : 已知的主机公钥清单//ssh命令远程连接不同服务器时可以选择接受到不同的公钥,会将这些主机的公钥都保存在这里
注意:
执行上面命令后,它要求你输入加密的一些附加参数,不用管,一般默认就好,一直回车即可生成秘钥。
②将客户端的公钥~/.ssh/id_rsa.pub
通过ssh-copy-id -i
拷贝到服务器
$ ssh-copy-id -i ~/.ssh/id_rsa.pub user@xxx.xxx.xxx.xxx
user代表Linux用户,xxx.xxx.xxx.xxx代表远程主机地址,下面为例子:
$ ssh-copy-id -i ~/.ssh/id_rsa.pub root@192.168.2.128
注意:
此时需要登录到user@xxx.xxx.xxx.xxx服务器的密码(没错,这里又用到了前面ssh密码登录里讲过的步骤),输入正确后即可在服务器生成公钥,该公钥保存在服务器家目录的.ssh
的authorized_keys
文件中(作用:存放远程免密登录的公钥,主要通过这个文件记录多台机器的公钥),然后退出即可。
③当客户端以后再发送连接请求,包括用户名、IP:
ssh root@xxx.xxx.xxx.xxx
④服务器得到客户端的请求后,就会到authorized_keys
中查找,如果有响应的用户名和IP,就会随机生成一个字符串;
⑤服务器将使用客户端拷贝过来的公钥进行加密,然后发送给客户端;
⑥得到服务器发送来的消息后,客户端会使用私钥进行解密,然后将解密后的字符串发送给服务器;
⑦服务器接收到客户端发送来的字符串后,跟之前的字符串进行对比,如果一致,就允许免密码登录。
是不是很方便呢?
禁用密码登陆
既然开启了SSH免密登陆,就可以把密码登陆关闭了。这样既可以快速连接远程服务器,也可以防止黑客攻击服务器,美滋滋啊。下面为具体步骤。
- 修改
/etc/ssh/sshd_config
文件:
vim /etc/ssh/sshd_config
- 将其中3行命令更改,前面若带#,就删掉,作用是可以用密钥登陆服务器:
RSAAuthentication yes
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys
- 然后在修改其中
PasswordAuthentication
属性为no
,即禁用密码登陆:
PasswordAuthentication no
- 重启sshd服务:
systemctl restart sshd.service
注
:本地密钥请保存好,远程服务器authorized_keys
中公钥也别乱修改。