概述
SSH
是(Secure SHell protocol)的简写,安全外壳协议(SSH)是一种在不安全网络上提供安全远程登录及其它安全网络服务的协议。OpenSSH
是 SSH(Secure SHell)协议的免费开源实现。SSH协议族可以用来进行远程控制,或在计算机之间传送文件。而实现此功能的传统方式,如telnet(终端仿真协议)、 rcp ftp、 rlogin、rsh都是极为不安全的,并且会使用明文传送密码。OpenSSH提供了服务端后台程序和客户端工具,用来加密远程控件和文件传输过程的中的数据,并由此来代替原来的类似服务。- 在过去我们使用的 rsh 和 telnet,因为包括登录时的 ID 和密码数据没有加密就传到网络上,存在安全上的问题。即使在内部网上,也有在因特网上的窃取和篡改等危险性。SSH 将包括密码在内的所有数据都已进行了加密处理,可以进行更安全的远程操作。在 SSH 中,由于协议标准的不同而存在 SSH1 和 SSH2 两个不同的版本。SSH2 是为了回避 SSH1 所使用的加密算法的许可证问题而开发的(现在这一许可证问题已经不存在了)。TLES 8中作为安装 SSH 协议的应用程序采用了开放源码的 OpenSSH。OpenSSH 与 SSH1 和 SSH2 的任何一个协议都能对应,但默认使用SSH2。
简单描述SSH运行的过程
- Client端向Server端发起SSH连接请求。
- Server端向Client端发起版本协商。
- 协商结束后Server端发送Host Key公钥 Server Key公钥,随机数等信息。到这里所有通信是不加密的。
- Client端返回确认信息,同时附带用公钥加密过的一个随机数,用于双方计算Session Key。
- 进入认证阶段。从此以后所有通信均加密。
- 认证成功后,进入交互阶段。
工作过程
ssh的工作过程共分为几步:
- TCP三次握手建立tcp链接;
- 版本协商阶段
- 算法协商阶段
- 密钥交换阶段
- 会话请求阶段
- 交互会话阶段
- TCP四次挥手断开tcp链接;
TCP的建立与断开
ssh在Internet中通常工作在TCP/IP层之上,基于tcp,端口使用22端口,所以在ssh开始前及结束后需要建立或者断开TCP链接;
三次握手:
四次挥手:
版本协商阶段
服务器及客户端在此步骤中交互各自的ssh版本及软件版本信息,过程如下:
在tcp建立链接之后,服务器向客户端发送“SSH-<主协议版本号>.<次协议版本号> - <软件版本号>”,客户端根据协议版本号,给出自己支持的版本号并发送给客户端,完成协商,否则断开tcp。
服务器向客户端发送自己的版本信息:
客户端回服务器自己的版本信息,完成协商:
算法协商
服务器端和客户端分别发送算法协商报文给对端,报文包含自己支持的公钥算法,加密算法,MAC算法,压缩算法等;
服务器&客户端发送的协商报文:
密钥交换阶段
ssh的密钥交换基于diffie-hellman-group-exchange-shaxxx<xxx如256>实现密钥的交换,过程如下:
client向server发送Exchange Request报文,开始密钥交换:
[](https://gitee.com/Bruce_Amadeus_Lee/mytp/raw/master/img/ssh-exchange requests.png)
server向client发送Group报文,与client共享DH算法中的P和G:
client将使用p与g计算出的e发送给server;
server收到e后,根据算法计算出秘钥K,然后使用sha256算法将一些已知信息hash加密为H,并用rsa将hash签名,最后发送rsa的公钥,dh的f值,rsa签名后的hash信息发回客户端:
同时server也会在相同的报文中发送验证无误后发送的new-key报文:
客户端根据服务器发回的f计算出K值,并根据同样的已有信息hash计算得到H后,使用服务器发来的rsa-公钥校验服务器发回的hash值的签名,根据得到的hash值H,再进行特定的hash运算即可得到以后用于数据加密的密钥,校验无误返回new key,表示密钥交换完毕,以后数据均会被数据加密密钥加密;
H的计算
H = hash(V_C|V_S|I_C|I_S|K_S||e||f||K);
tips:可以看H中有只有client和server才知道的值K,也包含rsa公钥,所以hash后,中间人无法更改里面的值,如果更改了rsa的公钥与H的签名,其实也是没有意义的,因为在H中包含一个不易破解的rsa公钥;所以唯一有问题的点在于,你开始就不是在和你的目的主机在协商,而是中间人;
类型 | 值 | 说明 |
---|---|---|
string | V_C | 客户端的初始报文(版本信息:SSH-2.0-xxx,不含结尾的CR和LF) |
string | V_S | 服务器的初始报文 |
string | I_C | 客户端 SSH_MSG_KEX_INIT的有效载荷(不含开头的数据长度值) |
string | I_S | 服务器的同上 |
string | K_S | 主机秘钥(dh gex reply(33)过程服务器发送host key (RSA公钥)) |
mpint | e | 客户端DH公钥 |
mpint | f | 服务器DH公钥 |
mpint | K | 共同DH计算结果 |
将以上内容顺序拼接后,使用sha256计算出H,会话第一次的密钥交换生成的H为session_id,之后再进行密钥交换的H不再是session_id,session_id不变;
加密密钥的计算
加密密钥是一个对称加密算法(一般为aes算法)所用到的密钥,用于实际的数据加密。
计算:hash(K,H,单个字符,session_id);
单个字符指的是单个大写的ASCII字母,根据不同的加密秘钥选择不同的字符来计算。
字母 | 秘钥 |
---|---|
‘A’ | 客户端到服务器的初始IV(CBC) |
‘B’ | 服务器到客户端的初始IV |
‘C’ | 客户端到服务器的加密秘钥(数据加解密秘钥) |
‘D’ | 服务器到客户端的加密秘钥 |
‘E’ | 客户端到服务器的完整性秘钥(HMAC) |
‘F’ | 服务器到客户端的完整性秘钥 |
哈希计算得到字符串RE,如果我么想要的秘钥长度比RE长,则在RE后面继续加上一个hash值:hash(K,H,RE)成为一个加长的RE。还不够继续加上hash(K,H,RE),依次类推
DH算法
dh算法最终目的是在不安全的网络上完成K值的传递:
- server生成两个数
G
与P
,P
为非常大的素数,为DH算法的mod;G
为密码发生器;,将P
与G
发送给client; - 客户端生成一个
x
(0<x<P),计算e
=(G^x)%P,e
就是客户端的公钥,客户端将e
发送给服务器; - 服务器也同客户端一样,生成一个数
y
,计算f
=(G^y)%P。将服务器公钥f
发送给客户端; - 服务端与客户端分别计算
K1
与K2
,可以证明K1
=K2
,所以K
= K1=(e^y)%P = K2= (f^x)%P,完成K
的传递;
如上,中间人可以看到G,P,e,f,只要P足够大,中间人就无法根据这几个值计算出K;
如下为一段破解的程序,在x,y及G与P不大的情况下,根据e和f猜测x和y并得出K:
1 | import random |
用户认证阶段
tips:完成密钥交换节点后,所有数据均使用加密密钥加密的密文包;
目前用户阶段主要使用两种方式,password认证及publickey认证:
password认证方式:
- 客户端向服务器发出password认证请求,同时将用户名密码发送给服务器;
- 服务器将用户名与密码与服务器上的进行对比,返回成功或失败;
publickey认证方式:
- 客户端生成RSA公钥和私钥;
- 客户端将自己的公钥存放到服务器;
- 客户端请求连接服务器,服务器将一个随机字符串发送给客户端;
- 客户端根据自己的私钥加密这个随机字符串之后再发送给服务器;
- 服务器接受到加密后的字符串之后用公钥解密,如果正确就让客户端登录,否则拒绝。
tips:ssh2中以上两种方式可以混合使用,比如两种均需要验证或只验证其中任意一种(and与or);
整体认证过程如下:
- 客户端向服务器端发送认证请求,认证请求中包含用户名、认证方法、与该认证方法相关的内容(如:password认证时,内容为密码)。
- 服务器端对客户端进行认证,如果认证失败,则向客户端发送认证失败消息,其中包含可以再次认证的方法列表。
- 客户端从认证方法列表中选取一种认证方法再次进行认证。
- 该过程反复进行, 直到认证成功或者认证次数达到上限, 服务器关闭连接为止。
配置linux服务器的公钥登陆
在client生成密钥对
支持多种非对称密钥生成算法,如dsa,ecdsa和rsa等;
1
2
3
4
5# -P参数表示密码,用于确保私钥的安全,可以使用ssh-agent来自动设置password的输入,一方方面是登陆方便,另一方面防止私钥丢失造成安全的隐患;
# -f指定存放密钥的文件,公钥/私钥存放同一目录,公钥为.pub
# -b采用长度为1024字节的公钥/私钥对,最长4096;
ssh-keygen -b 2048 -t rsa -P
# 该命令将在/root/.ssh目录下面产生一对密钥id_rsa和id_rsa.pub将client下面的id_rsa.pub复制到Server的/root/.ssh/authorized_keys
1
2
3
4
5# 如果.ssh/authorized_keys不存在则需要手动创建
scp /root/.ssh/id_rsa.pub root@server_ip:/root/.ssh/authorized_keys
# 复制到某个用户的home下,即对某个用户的验证,比如这里,登陆上来即是root用户
chmod 600 /root/.ssh/authorized_keys
# 只有root或当前用户才可以访问这个目录,这个是必须的,否则这个目录ssh会认为无效;可以关闭密码登陆:
1
2
3vim /etc/ssh/sshd_config
PasswordAuthentication:no
systemctl restart sshd
会话与交换阶段
会话请求后即计入交互会话阶段:
- 服务器等待客户端的请求;
- 认证通过后,客户端向服务器发送会话请求;
- 服务器处理客户端的请求。请求被成功处理后, 服务器会向客户端回应 SSH_SMSG_SUCCESS包,SSH进入交互会话阶段;否则回应 SSH_SMSG_FAILURE包,表示服务器处理请求失败或者不能识别请求。
- 客户端将要执行的命令加密后传给服务器;
- 服务器接收到报文,解密后执行该命令,将执行的结果加密发还给客户端;
- 客户端将接收到的结果解密后显示到终端上.