一、作用
ssh(Security Shell)是用来实现安全远程管理的一个协议。相比于telnet,使用ssh能够有效地解决信息泄露的问题。
二、算法及交互过程
ssh建立连接主要有以下五个步骤:
①协商ssh版本
②协商将要使用的各种算法
③通过Diffie-Hellman算法得到之后通信所使用的密钥
④认证阶段,服务器对客户端进行身份验证
⑤认证成功之后,客户端请求发起会话,服务器确认之后即可开始信息交互
2.1.协商ssh版本
①客户端向服务器发起连接请求,ssh协议基于TCP,默认端口为22
②服务器把自己的ssh协议版本号发送给客户端
③客户端知道了服务器所使用的版本后,选择相同或者能够兼容服务器的版本,将版本信息发送给服务器
④服务器判断是否支持客户端要使用的版本,如果支持,将进入算法和密钥的协商阶段,否则关闭此连接
2.2.算法协商
①客户端发送自己支持的公钥算法列表,加密算法列表,MAC算法列表,压缩算法列表
②服务器回复ack报文确认,并发送自己支持的各种算法列表
③双方开始协商要使用的各种算法,这里的协商以客户端为主 ,按客户端各算法列表从左至右开始匹配(例如加密算法中,最左边的aes128-cbc的优先级是最高的),如果服务器支持相应的算法,则匹配成功,如果匹配到最后都不支持,则协商失败
2.3.密钥协商
由于使用的是SSH2.0版本,会话密钥的协商方式使用Diffie-Hellman算法。这里简单地介绍一下这个算法:
Diffie-Hellman算法是Whitefield Diffie和Martin Hellman在1976年公布的一种密钥交换算法,它的有效性依赖于计算离散对数的难度
现客户端A要和服务器B交换密钥:
服务器B规定一个素数P,一个整数G,G是P的原根
客户端生成自己的私用密钥a(a<q),并计算公开密钥e=G^a mod P,把e发送给服务器B
服务器生成自己的私用密钥b(b<q),并计算公开密钥f=G^b mod P,把f发送给客户端A
客户端A可以通过自己的私用密钥a和服务器的公开密钥f算出共享密钥 K=f^a mod P
服务器B可以通过自己的私用密钥b和客户端的公开密钥e算出共享密钥 K=e^b mod P
二者计算的结果K值是一致的,从而完成了密钥交换
a和b对其他人是保密的,攻击者只能离散对数来确定密钥
大致协商过程如下,由客户端首先发起请求
①客户端发出的第一个报文说明了密钥交互参数:Min、Number of Bits、Max
②服务器端收到客户端DH请求后,设定P和G发送给客户端,P是一个大素数,满足客户端刚刚发来的那些要求,G是大于1的数,通常取2或者5
③客户端收到P和G后,生成自己的私钥a,并根据a计算出自己的公钥e,并把e发送给服务器端
④服务器也会生成自己的私钥b并计算出公钥f,收到客户端发来的e后,利用b和e生成共享密钥K,接着把f发给客户端,用于客户端计算共享密钥K
KEX DH host key是服务器的主机公钥(通常是RSA)
KEX DH H Signature是服务器用主机私钥对计算出的哈希值H进行签名的结果
H的值是将客户端初始报文、服务器初始报文、客户端DH公钥、服务器DH公钥等参数进行哈希的结果
⑤客户端接受到f之后,计算出共享密钥K,然后服务器一样计算出H的值,并用服务器的公钥解密KEX DH H Signature,将结果与自己计算的H值比较,如果一致,就会向服务器发送New Keys报文,双方密钥交换成功。计算出的H作为会话ID,K作为之后通信过程中的加密密钥
2.4.认证及交互阶段
共享密钥协商成功之后,数据报文都被加密,只能看到加密后的结果:
认证方式有两种:
- 用户名密码认证
①客户端发起认证请求,服务器回复其公钥
②客户端使用服务器的公钥将其用户名密码加密后发给服务器
③服务器使用自己的私钥解密,验证结果 - 公钥私钥认证
①客户端发送登录的ip和用户名,服务器识别该客户端的公钥(在authorized_keys文件中),利用该公钥加密一段随机字符串发送刚给客户端
②客户端使用私钥解密,得到随机字符串后发送给服务器
③服务器收到该字符串,若与其之前生成的一致,即说明公私钥匹配,认证成功
注:要使用该认证方式需要事先在客户端生成公私钥,并把公钥存放在服务器上
三、SSH相关应用
3.1.Linux的下ssh
linux系统中,一般默认都安装了ssh客户端及服务端。ssh服务的相关进程是sshd,可以使用servcie sshd status(CentOS6)查看当前该服务的运行状态。
3.1.1.ssh client
- 最简单的登录:ssh user@ip,如ssh root@1.1.1.1
ssh命令有关参数:
-A:开启认证代理连接转发功能
-a:关闭认证代理连接转发功能
-b:使用本地指定地址作为对应连接的源ip
-f:后台执行ssh指令
-i:指定身份文件
-p:指定远程服务器端口
-N:不执行远程指令
- 如果远程服务器默认端口不是22(可以设置一个高位端口,比如10024),则需要指定端口:ssh user@ip -p 10024
如果我们要经常使用某个远程主机,可以通过配置$HOME/.ssh/config文件更方便地进行连接
vim ~/.ssh/config #当前是root用户
Host test
StrictHostKeyChecking no #第一次连接新的主机时,自动接收公钥,无需提示。
HostName 1.1.1.1
Port 22
ForwardAgent yes
User root
Controlpath ~/.ssh/ssh-%r@%h:%p.sock
以后只需要ssh test即可.
ssh客户端的读取顺序如下
①命令行
②$HOME/.ssh/config
③/etc/ssh/ssh_config(所有用户使用的配置文件)
3.1.2. ssh server
配置文件:/etc/ssh/sshd_config
Port 22 #ssh监听的端口,可以写多个
ListenAddress 10.104.45.112 #可以指定监听的具体地址,默认是注释的,表示监听0.0.0.0
Protocol 2 #使用sshv2
PasswordAuthentication yes #密码认证
X11Forwarding yes #允许本地主机上执行远程主机的GUI程序
PermitRootLogin yes #允许root登录
AllowUsers xxx #只允许xxx用户登录的用户
...
修改完配置文件之后,需要重启服务才能生效
3.2.利用ssh反向代理访问内网主机
如果要远程访问一台内网主机,有两种方式:
- 通过静态NAT或PAT将内网主机的地址/端口映射到公网
- 借助一台公网服务器,利用ssh反向代理来访问内网主机
3.2.1.方法一:静态NAT或PAT
一般只有企业的网络管理员能使用这种方法,可以通过静态NAT将内网主机的地址转化为一个公网地址(一般拥有大量公网地址才会这么做),或者使用PAT将内网主机的端口映射到公网地址的某个端口,这里就简单地给出路由器上的配置:
#静态NAT:将内网主机地址192.168.1.100映射为公网地址1.1.1.1
Cisco Router:
ip nat inside source static 192.168.1.100 1.1.1.1
HuaWei Router:
nat static global 1.1.1.1 inside 192.168.1.100
#PAT:内网主机的22端口映射到公网地址22122端口
Cisco Router:
ip nat inside source static tcp 192.168.1.100 22 1.1.1.1 22122
HuaWei Router:
nat static protocol tcp global current-interface 22122 inside 192.168.1.100 22
3.2.2.方法二:ssh反向代理
大部分情况下,我们无法管理公网地址,接下来介绍第二种方法,此方法需要借助一台公网服务器:
公网主机A: ip——1.1.1.1 sshd端口——22
内网主机B: ip——192.168.1.100 sshd端口——22
首先在内主机B上:
ssh -NfR 1234:localhost:22 root@1.1.1.1
将A的1234端口和B的22端口绑定
接着在外网主机A上:
netstat -ano | grep 1234
tcp 0 0 127.0.0.1:1234 0.0.0.0:* LISTEN off (0.00/0/0)
可以看到本地在监听1234端口
接着使用以下命令就可以从公网主机A上访问内网主机B了
ssh localhost -p 1234
通过以上方式,已经可以实现我们的需求,接下来可以做一些优化:
- 使用公私钥登录,无需在登录的时候输入密码
第一步:在内网服务器B上生成公私钥
ssh-keygen -t rsa #一直按回车,使用默认选项即可
成功后在~/.ssh/目录下就会生成id_rsa(私钥)和id_rsa.pub (公钥文件)
第二步:将B的公钥放到外网主机A的~/.ssh/authorized_keys
ssh root@1.1.1.1 'mkdir -p ~/.ssh && cat >> .ssh/authorized_keys' < ~/.ssh/id_rsa.pub
或者使用
ssh-copy-id root@1.1.1.1
- 使用autossh维护反向连接
yum install -y autossh
...
autossh -M 8888 -NR 1234:localhost:22 root@1.1.1.1 -p 22
autossh的命令跟ssh差不多,默认后台运行,所以无需加-f
-M选项表示维护程序监听8888端口,保证连接的可用性,如果断掉,则会重新连接