百度百科中的解释:SSH 为 Secure Shell 的缩写,由 IETF 的网络小组(Network Working Group)所制定;SSH 为建立在应用层基础上的安全协议。SSH 是较可靠,专为远程登录会话和其他网络服务提供安全性的协议。利用 SSH 协议可以有效防止远程管理过程中的信息泄露问题。SSH最初是UNIX系统上的一个程序,后来又迅速扩展到其他操作平台。SSH在正确使用时可弥补网络中的漏洞。SSH客户端适用于多种平台。几乎所有UNIX平台—包括HP-UX、Linux、AIX、Solaris、Digital UNIX、Irix,以及其他平台,都可运行SSH。
简单来说,ssh是一种网络协议,是一个提供数据通信安全、远程登录、远程指令执行等功能的安全网络协议(允许用户远程向服务器发送shell命令,并让它们执行),最初提出目的是替代非安全的Telnet(23端口,没有使用加密连接)、rsh、rexec等远程Shell协议。之后SSH发展了两个大版本SSH-1和SSH-2。如果一个用户从本地计算机,使用ssh协议登录另一台远程计算机,我们就可以认为,这种登录是安全的,即使被中途截获,密码也不会泄露。需要指出的是,ssh只有一种协议,存在多种实现(OpenSSH: ssh协议的开源实现,dropbear:另一个开源实现)。
1)1. 1.x版本
1995年,芬兰赫尔辛基理工大学的研究员Tatu Ylönen设计了ssh协议的第一个版本(现称SSH-1),目标是取代早期的rlogin, TELNET, ftp和rsh这些不安全的协议。同年七月,他以免费软件的形式发布了这个协议的一个实现,并迅速流行起来。
1995年12月,Ylonen创建了SSH Communications Security来发展和商业化SSH,SSH软件的原始版本使用了各种免费软件,如Gun libgmp,但是后来由SSH Communications Security发布的版本逐渐演化为私有软件。
2)2.x版本
“Secsh”,IETF工作小组的官方互联网工程任务组,负责SSH协议的第二版本。在2006年,他们发布了SSH协议修订版,即SSH-2,并被采纳为标准。该版本与SSH-1不兼容,但在安全性和特性方面都优于SSH-1。更好的安全性,例如,通过Diffie-Hellman密钥交换和通过信息认证码进行强大的完整性检查。SSH-2的新特性,增加了在单个SSH连接上运行任意数量的shell会话的能力。由于SSH-2比SSH-1更有优势而且受欢迎,一些实现如Lsh和Dropbear仅支持SSH-2协议。
3)1.99版本
在2006年1月,在2.1版本建立之后,RFC 4253指定一个支持ssh2.0以及兼容之前版本的SSH服务的协议版本为1.99。这不是一个实际的版本,而是一种识别向后兼容性的方法。
4)OpenSSH and OSSH
早在1999年,很多开发人员都很想要一个可用的免费版本,他们找到了SSH源程序的1.2.12发布版本,这是它在开放源码许可下发布的最后一个版本,Bjorn Gronvall的OSSH就是后来以这个为基础发展出来的。不久,OpenBSD开发人员在Gronvall的代码的基础上开了一个分支,并对其进行了大量的工作后,创建了OpenSSH,这是由2.6版本的OpenBSD发布的。在这个版本中,一个“可移植性”分支被创建了,目的是让OpenSSH能在其他操作系统中使用。
到了2005年,OpenSSH已经是最流行的SSH实现了,没有之一,在很多操作系统中都默认安装OpenSSH。与此同时,OSSH却过时了。OpenSSH一直在维护并支持SSH-2协议,在7.6版本的OpenSSH代码库中,去除了对SSH-1的支持。
1)使用某个用户(例如user)登录远程主机host
命令:ssh user@host
2)如果本地用户名和远程用户名一致,则登录时可以省略用户名
命令:ssh host
3)ssh的默认端口是22,也就是说,你的登录请求会送进远程主机的22端口。使用-p参数,可以修改这个端口
命令:ssh –p 端口号 user@host
OpenSSH是基于C/S架构工作的。分为服务端和客户端。在Linux系统中,SSH相关进程有这么几个:ssh或者ssh-agent,sshd。
1)ssh,对应ssh client,一般Linux的发行版本默认都会安装;
2)sshd,对应的是ssh server,有的Linux发行版本需要自己安装,比如Ubuntu的Desktop版本;(服务端进程,配置文件在/etc/ssh/sshd_config)
3)ssh-agent,是ssh代理程序,它可以帮助我们管理私钥。(我安装的Ubuntu20.04和CentOS7默认都是有这个的)(客户端进程,配置文件在/etc/ssh/ssh_config)
1)客户端配置文件/etc/ssh/ssh_config
/etc/ssh/ssh——config
# Host * # Host指令是ssh_config中最重要的指令,只有ssh连接的目标主机名能匹配此处给定模式时,才允许连接
# 下面一系列配置项直到出现下一个Host指令才对此次连接生效
# ForwardAgent no #设置连接是否经过验证代理(如果存在)转发给远程计算机
# ForwardX11 no #设置X11连接是否被自动重定向到安全的通道和显示集(DISPLAY set)
# RhostsRSAAuthentication no #设置是否使用基于rhosts的安全验证。
# RSAAuthentication yes #设置是否使用用RSA算法的基于rhosts的安全验证。
# PasswordAuthentication yes # 是否启用基于密码的身份认证机制
# HostbasedAuthentication no # 是否启用基于主机的身份认证机制
# GSSAPIAuthentication no # 是否启用基于GSSAPI的身份认证机制
# GSSAPIDelegateCredentials no
# GSSAPIKeyExchange no
# GSSAPITrustDNS no
# BatchMode no # 如果设置为"yes",将禁止passphrase/password询问。比较适用于在那些不需要询问提供密
# 码的脚本或批处理任务任务中。默认为"no"。
# CheckHostIP yes
# AddressFamily any
# ConnectTimeout 0
# StrictHostKeyChecking ask # 设置为"yes",ssh将从不自动添加host key到~/.ssh/known_hosts文件,且拒绝连接那些未知的主机(即未保存host key的主机或host key已改变的主机)。
# 它将强制用户手动添加host key到~/.ssh/known_hosts中。
# 设置为ask将询问是否保存到~/.ssh/known_hosts文件。
# 设置为no将自动添加到~/.ssh/known_hosts文件。
# IdentityFile ~/.ssh/identity # ssh v1版使用的私钥文件
# IdentityFile ~/.ssh/id_rsa # ssh v2使用的rsa算法的私钥文件
# IdentityFile ~/.ssh/id_dsa # ssh v2使用的dsa算法的私钥文件
# Port 22 # 当命令行中不指定端口时,默认连接的远程主机上的端口
# Protocol 2,1
# Cipher 3des # 指定ssh v1版本中加密会话时使用的加密协议
# Ciphers aes128-ctr,aes192-ctr,aes256-ctr,arcfour256,arcfour128,aes128-cbc,3des-cbc # 指定ssh v1版本中加密会话时使用的加密协议
# MACs hmac-md5,hmac-sha1,[email protected],hmac-ripemd160
# EscapeChar ~
# Tunnel no
# TunnelDevice any:any
# PermitLocalCommand no # 功能等价于~/.ssh/rc,表示是否允许ssh连接成功后在本地执行LocalCommand指令指定的命令。
# LocalCommand # 指定连接成功后要在本地执行的命令列表,当PermitLocalCommand设置为no时将自动忽略该配置
# %d表本地用户家目录,%h表示远程主机名,%l表示本地主机名,%n表示命令行上提供的主机名,
# p%表示远程ssh端口,r%表示远程用户名,u%表示本地用户名。
# VisualHostKey no # 是否开启主机验证阶段时host key的图形化指纹
Host *
GSSAPIAuthentication yes
2)客户端配置文件/etc/ssh/sshd_config
/etc/ssh/sshd_config
#配置文件概要
[root@localhost ~]# cat /etc/ssh/sshd_config
#Port 22 # 服务端SSH端口,可以指定多条表示监听在多个端口上
#ListenAddress 0.0.0.0 # 监听的IP地址。0.0.0.0表示监听所有IP,指定IP只监听指定的IP
Protocol 2 # 使用SSH 2版本, 如果要同时支持两者,就必须要使用 2,1 这个分隔了
#####################################
# 私钥保存位置 #
#####################################
# HostKey for protocol version 1
#HostKey /etc/ssh/ssh_host_key # SSH 1保存位置/etc/ssh/ssh_host_key
# HostKeys for protocol version 2
#HostKey /etc/ssh/ssh_host_rsa_key # SSH 2保存RSA位置/etc/ssh/ssh_host_rsa _key
#HostKey /etc/ssh/ssh_host_dsa_key # SSH 2保存DSA位置/etc/ssh/ssh_host_dsa _key
###################################
# 杂项配置 #
###################################
#PidFile /var/run/sshd.pid # 服务程序sshd的PID的文件路径
#ServerKeyBits 1024 # 服务器生成的密钥长度
#SyslogFacility AUTH # 使用哪个syslog设施记录ssh日志。日志路径默认为/var/log/secure
#LogLevel INFO # 记录SSH的日志级别为INFO
#LoginGraceTime 2m # 身份验证阶段的超时时间,若在此超时期间内未完成身份验证将自动断开
###################################
# 以下项影响认证速度 #
###################################
#UseDNS yes # 指定是否将客户端主机名解析为IP,以检查此主机名是否与其IP地址真实对应。默认yes。
# 由此可知该项影响的是主机验证阶段。建议在未配置DNS解析时,将其设置为no,否则主机验证阶段会很慢
###################################
# 以下是和安全有关的配置 #
###################################
#PermitRootLogin yes # 是否允许root用户登录
#MaxSessions 10 # 最大客户端连接数量
#GSSAPIAuthentication no # 是否开启GSSAPI身份认证机制,默认为yes
#PubkeyAuthentication yes # 是否开启基于公钥认证机制
#AuthorizedKeysFile .ssh/authorized_keys # 基于公钥认证机制时,来自客户端的公钥的存放位置
PasswordAuthentication yes # 是否使用密码验证,如果使用密钥对验证可以关了它
#PermitEmptyPasswords no # 是否允许空密码,如果上面的那项是yes,这里最好设置no
StrictModes yes # 当使用者的 host key 改变之后,Server 就不接受联机,可以抵挡部分的木马程序!
#RSAAuthentication yes # 是否使用纯的 RSA 认证!?仅针对 version 1 !
###################################
# 以下可以自行添加到配置文件 #
###################################
DenyGroups hellogroup testgroup # 表示hellogroup和testgroup组中的成员不允许使用sshd服务,即拒绝这些用户连接
DenyUsers hello test # 表示用户hello和test不能使用sshd服务,即拒绝这些用户连接
###################################
# 以下一项和远程端口转发有关 #
###################################
#GatewayPorts no # 设置为yes表示sshd允许被远程主机所设置的本地转发端口绑定在非环回地址上
# 默认值为no,表示远程主机设置的本地转发端口只能绑定在环回地址上
3)指定可以登录的主机和不可以登录的主机
方法一、修改文件/etc/hosts.allow和/etc/hosts.deny
hosts.allow添加:sshd:ip:allow
hosts.deny添加:sshd:ip:deny
方法二、修改文件/etc/ssh/sshd_config
AllowUsers root@ip ##允许主机ip ssh登录
DenyUsers root@ip ##禁止主机ip ssh登录
ssh的登录日志存放在文件/var/log/secure
缩略语 |
英文全名 |
中文解释 |
AAA |
Authentication, Authorization, Accounting |
认证、授权、计费 |
AES |
Advanced Encryption Standard |
高级加密标准 |
DES |
Data Encryption Standard |
数据加密标准 |
DSA |
Digital Signature Algorithm |
数字签名算法,非对称密钥算法的一种 |
FTP |
File Transfer Protocol |
文件传输协议 |
MAC |
Message Authentication Code |
消息验证码 |
RSA |
Rivest Shamir and Adleman |
非对称密钥算法的一种 |
SFTP |
Secure File Transfer Protocol |
安全的文件传输协议 |
SSH |
Secure Shell |
安全外壳 |
Stelnet |
Secure Telnet |
安全的Telnet |
ECDSA | Elliptic Curve Digital Signature Algorithm | 椭圆曲线数字签名算法 |
SSH协议采用客户端/服务器(C/S)架构,分为传输层、认证层和连接层。
1)传输层协议
传输层协议主要用来在客户端和服务器之间建立一条安全的加密通道,为用户认证、数据交互等对数据传输安全性要求较高的阶段提供足够的机密性保护。传输层提供了如下功能:
数据真实性检查、数据完整性检查、为客户端提供了对服务器进行认证的功能,传输层协议通常运行在TCP/IP连接之上(服务器端使用的知名端口号为22),也可以运行在其他任何可以信赖的数据连接之上。
2)认证层协议
认证层协议运行在传输层协议之上,完成服务器对登录用户的认证。
3)连接层协议
连接层协议负责在加密通道上划分出若干逻辑通道,以运行不同的应用。它运行在认证层协议之上,提供交互会话、远程命令执行等服务。
在了解SSH安全机制之前,先了解一下两种加密方式:对称加密和非对称加密
1)对称加密
对称加密:也称为秘钥加密,即加密和解密使用一样的算法,只要解密时提供与加密时一致的密码就可以完成解密。例如QQ登录密码,银行卡密码,只要保证密码正确就可以。
对称加密的强度高,很难破解。但是就如何安全的保存秘钥呢?考虑到数量庞大的Client端,很难保证密钥不被泄露。一旦一个Client端的密钥被窃据,那么整个系统的安全性也就不复存在。为了解决这个问题,非对称加密应运而生。
2)非对称加密
非对称加密:非对称加密有两个密钥:“公钥”和“私钥”,通过公钥(public key)和私钥(private key)来加密、解密。两个密钥的特性:公钥加密后的密文,只能通过对应的私钥进行解密。而通过公钥推理出私钥的可能性微乎其微。
下面看下使用非对称加密方案的登录流程:
(私钥不能在网络中传输-----私钥可以解密公钥,公钥可以在网络中传输-----公钥不能解密私钥。私钥是Server端独有,这就保证了Client的登录信息即使在网络传输过程中被窃据,也没有私钥进行解密,保证了数据的安全性,这充分利用了非对称加密的特性。)
SSH协议需要解决Telnet协议明文传输的缺陷,它通过以下两方面保证数据传输的机密性:在通信双方之间建立加密通道,保证传输的数据不被窃听、使用密钥交换算法保证密钥本身的安全。
a、 使用加密通道保证数据不被窃听
所谓加密通道,是指发送方在发送数据前,使用加密密钥对数据进行加密,然后将数据发送给对方;接收方接收到数据后,利用解密密钥从密文中获取明文。加解密算法分为两类:
对称密钥算法:数据加密和解密时使用相同的密钥和相同的算法。
非对称密钥算法:数据加密和解密时使用不同的密钥,一个是公开的公钥,一个是由用户秘密保存的私钥。
由于非对称密钥算法比较耗时,一般多用于数字签名以及身份认证。SSH加密通道上的数据加解密使用对称密钥算法,目前主要支持的算法有DES、3DES、AES等,这些算法都可以有效地防止交互数据被窃听,而且由于采用了初始化向量保护,可以防止类似于密码流复用等密码分析工具的攻击。
b、使用密钥交换算法保证密钥本身的安全
对称密钥算法要求解密密钥和加密密钥完全一致,才能顺利从密文中解密得到明文。因此,要建立加密通道,必须先在通信双方部署一致的加解密密钥。部署加解密密钥的方式有多种:手工配置和第三方机构分配等。手工配置的方式扩展性差,只适合一些小型的本地网络;使用第三方机构分配密钥的方式,需要额外的第三方服务器,而且密钥在网络中传输容易被窃听。
SSH协议使用一种安全的方式在通信双方部署密钥:密钥交换算法。利用密钥交换算法可以在通信双方动态地产生密钥,这个密钥只能被通信的双方获得,任何第三者都无法窃听,这就在源头上保证了加解密使用密钥的安全性,很好地解决了密钥分发问题。
密钥交换算法的基本原理是:
(1) 客户端随机选择一个私钥Xc,1
(2) 服务器也随机生成一个私钥Xs,1
(3) 服务器接收到客户端发送过来的Yc,按照下面的公式计算出密钥:
K = (Yc)^Xs mod p
(4)客户端收到服务器端发送过来的Ys,同样按照下面的公式计算出密钥:
K = (Ys)^Xc mod p
通过上面的方法,客户端和服务器端就可以获得相同的密钥。
由上面的分析可以看出,密钥交换算法的安全性建立在计算离散对数的难度之上。算式Y=g^x mod p中,由X计算Y是很容易的,但是要由Y计算X是非常困难的。在密钥交换算法中对外公开的只有p、g、Yc和Ys,私钥Xc和Xs是保密的,其他用户即便获取了p、g、Yc和Ys也很难推断出私钥Xc和Xs,从而保证了密钥的安全性。
密钥交换算法具有如下优势:扩展性更好,不需要网络管理员的多余配置;交换得到的密钥是保存在内存中,不易被读取和篡改;每个连接都会动态生成一次新的密钥,安全性更高。
Client端如何保证接受到的公钥就是目标Server端的?如果有人截获了登录请求,然后冒充远程主机,将伪造的公钥发给用户,那么用户很难辨别真伪。因为不像https协议,SSH协议的公钥是没有证书中心(CA)公证的,也就是说,都是自己签发的。可以设想,如果攻击者插在用户与远程主机之间(比如在公共的wifi区域),用伪造的公钥,获取用户的登录密码。再用这个密码登录远程主机,那么SSH的安全机制就荡然无存了。这种风险就是著名的"中间人攻击"。
为了防止类似这样的伪服务器欺骗,SSH协议支持客户端对服务器端进行认证。服务器端在密钥交换阶段,使用自己的私钥对一段固定格式的数据进行数字签名,并将该签名发往客户端,客户端使用本地保存的服务器公钥,对签名进行鉴别,从而达到认证服务器的目的。客户端对服务器进行认证的基础是本端存储的服务器公钥是真实服务器的公钥。因此,需要保证客户端获取的服务器公钥是正确的。
为了防止非法用户登录到设备,对设备进行破坏性配置,SSH协议需要支持多种用户认证方式,提高对用户认证的强度。常用的用户认证方式包括密码认证和公钥认证。
1)密码认证(基于口令的认证)
SSH协议可以利用AAA提供的认证功能,完成对登录用户进行密码认证。根据AAA采取的认证策略的不同,密码认证分为本地认证和远程认证(远端的RADIUS等认证服务器上认证)两种方式。
在https中可以通过CA来进行公证,可是SSH的publish key和private key都是自己生成的,没法公证。只能通过Client端自己对公钥进行确认。通常在第一次登录的时候,系统会出现下面提示信息:
以我在虚拟机中开启的两台服务器为例:一台CentOS7(配置IP:192.168.1.122),一台ubuntu20.04(配置IP:192.168.1.101)
注:这里说明下采用何种加密方式在配置文件中配置,起初ssh 192.168.1.101时, 192.168.1.101服务器中的sshd_config的加密方式都被注释了,ubuntu20.04应该是默认了使用ECDSA加密方式
#HostKey /etc/ssh/ssh_host_rsa_key
#HostKey /etc/ssh/ssh_host_ecdsa_key
#HostKey /etc/ssh/ssh_host_ed25519_key
当我修改配置文件,将HostKey /etc/ssh/ssh_host_rsa_key前面的#号去掉后systemctl restart sshd重启一下,再执行发现加密方式变成了RSA加密,关于算法,后面再详细介绍。
上面的信息说的是:无法确认主机的真实性,不过知道它的公钥指纹,是否继续连接?(之所以用fingerprint代替key,主要是key过于长(RSA算法生成的公钥有1024位),很难直接比较。所以,对公钥进行hash生成一个128位的指纹,这样就方便比较了。)
如果输入yes后,会出现下面信息:
该host已被确认,并被追加到文件known_hosts中,然后就需要输入密码,密码验证通过即可登录成功。
注:known_hosts中存储是已认证的远程主机host key,每个SSH Server都有一个secret, unique ID, called a host key。
2)基于公钥认证
在上面介绍的登录流程中可以发现,每次登录都需要输入密码,很麻烦。SSH提供了另外一种可以免去输入密码过程的登录方式:公钥登录。
认证过程:
SSH的报文交互主要有以下几个阶段:连接建立、版本协商、 算法协商、密钥交换、用户认证、服务请求、数据传输和连接关闭
1)连接建立连接建立
SSH服务器端在22端口侦听客户端的连接请求,接收到客户端的连接建立请求后,与客户端进行三次握手,建立起一条TCP连接,后续的所有报文交互都在这个TCP连接之上进行。
2)版本协商
TCP连接建立之后,服务器向客户端发送第一个报文,包括版本标志字符串,格式为“SSH-<主协议版本号>.<次协议版本号>-<软件版本号>”,协议版本号由主版本号和次版本号组成,软件版本号主要是为调试使用。客户端收到报文后,解析该数据包,如果服务器端的协议版本号比自己的低,且客户端能支持服务器端的低版本,就使用服务器端的低版本协议号,否则使用自己的协议版本号。客户端回应服务器一个报文,包含了客户端决定使用的协议版本号。服务器比较客户端发来的版本号,决定是否能同客户端一起工作。如果协商成功,则进入密钥和算法协商阶段,否则服务器端断开 TCP连接。(版本号协商阶段报文都是采用明文方式传输的)
3)算法协商
SSH协议报文交互需要使用多种算法:
用于产生会话密钥的密钥交换算法,包括diffie-hellman-group-exchange-sha1、diffie-hellman-group1-sha1和diffie-hellman-group14-sha1算法等。
用于数据信息加密的加密算法,包括3des-cbc、aes128-cbc和des-cbc加密算法等。
用于进行数字签名和认证的主机公钥算法,包括RSA和DSA公钥算法等。
用于数据完整性保护的MAC算法,包括hmac-md5、hmac-md5-96、hmac-sha1和hmac-sha1-96算法等。
由于各种客户端和服务器对这些算法的支持情况不一样,因此需要通过算法协商阶段,使客户端和服务器协商出双方都支持的算法。
SSH协议的算法协商过程为:
a、客户端和服务器端都将自己支持的算法列表发送给对方;
b、双方依次协商每一种算法(密钥交换算法、加密算法等)。每种算法的协商过程均为:从客户端的算法列表中取出第一个算法,在服务器端的列表中查找相应的算法,如果匹配上相同的算法,则该算法协商成功;否则继续从客户端算法列表中取出下一个算法,在服务器端的算法列表中匹配,直到匹配成功。如果客户端支持的算法全部匹配失败,则该算法协商失败。
c、某一种算法协商成功后,继续按照上述方法协商其他的算法,直到所有算法都协商成功;如果某一种算法协商失败,则客户端和服务器之间的算法协商失败,服务器断开与客户端的连接。
4)密钥交换
加密算法协商成功后,服务器端和客户端利用 DH交换(Diffie-Hellman Exchange)算法、主机密钥对等参数,生成会话密钥和会话 ID,并能够有效防止第三方窃听加解密密钥。
5)用户认证
密钥交换完成之后,进入用户认证阶段。
a、 客户端向服务器端发送认证请求报文;
b、服务器收到认证请求,回复认证报文,其中携带服务器支持、且需要该用户完成的认证方式列表;
c、客户端从服务器发送给自己的认证方式列表中选择某种认证方式,向服务器发起认证请求,认证请求中包含用户名、认证方法、与该认证方法相关的内容(如:password认证时,内容为密码,公钥认证方式中,内容为用户本地密钥对的公钥部分(公钥验证阶段))
d、服务器接收到客户端的认证请求,验证客户端的认证信息;
e、服务器根据本端上该用户的配置,以及用户认证的完成情况,决定是否需要客户端继续认证;
f、该过程反复进行, 直到认证成功或者认证次数达到上限, 服务器关闭连接为止;
注:SSH提供两种认证方式(SSH2.0还提供了,password-publickey 认证和 any 认证)
password认证:密码认证
publickey 认证:密钥或数字签名认证
password-publickey 认证:认证方式为 password 和 publickey认证同时满足
any认证:指定该用户的认证方式可以是 password,也可以是 publickey
SSH协议支持多种应用服务。用户成功完成认证后,SSH客户端向服务器端发起服务请求,请求服务器提供某种应用。
a、客户端发送SSH_MSG_CHANNEL_OPEN消息,请求与服务器建立会话通道,即session;
b、服务器端收到SSH_MSG_CHANNEL_OPEN消息后,如果支持该通道类型,则回复SSH_MSG_CHANNEL_OPEN_CONFIRMATION消息,从而建立会话通道;
c、会话通道建立之后,客户端可以申请在通道上进行shell或subsystem类型的会话,分别对应SSH和SFTP两种类型的服务。
服务请求成功,建立会话后,服务器和客户端可以在该会话上进行数据的传输。客户端将要执行的命令加密后传给服务器,服务器接收到报文,解密后执行该命令,将执行的结果加密发送给客户端,客户端将接收到的结果解密后显示到终端上。
通信结束或用户空闲时间超时后,关闭会话,断开连接。
案例:客户端(ubuntu20.04 192.168.18.163) 服务端(CentOS192.168.18.162),并且/etc/ssh/sshd_config中已设置好支持密钥登录
SSH登录是用的RSA非对称加密的,所以我们在SSH登录的时候就可以使用RSA密钥登录,SSH有专门创建SSH密钥的工具ssh-keygen;
首先进入客户端(ubuntu20.04 192.168.18.163)系统的用户目录下的.ssh目录下,root用户是/root/.ssh(~/.ssh),一般这里面会出现这个文件分别是:
a、id_rsa:保存私钥
b、id_rsa.pub:保存公钥
c、authorized_keys:保存已授权的客户端公钥
d、known_hosts:保存已认证的远程主机ID
1)进入目录:.ssh --》 cd /root/.ssh 或者 cd ~/.ssh
root@hls-virtual-machine:~# cd ~/.ssh
root@hls-virtual-machine:~/.ssh# ls
known_hosts
只有一个文件,known_hosts,如果没有进行过ssh密钥创建是长这样子。
2)生成密钥:ssh-keygen -t rsa -b 4096
ssh-keygen -t rsa -b 4096
也可以不加-b参数,直接使用ssh-keygen -t rsa,执行密钥生成命令,一路回车就可以了
root@hls-virtual-machine:~/.ssh# ssh-keygen -t rsa -b 4096
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /root/.ssh/id_rsa
Your public key has been saved in /root/.ssh/id_rsa.pub
The key fingerprint is:
SHA256:nveshBKD8VCBtmRepBZdMY5ESyko1C5/nYlDMbpFbMA root@hls-virtual-machine
The key's randomart image is:
+---[RSA 4096]----+
|..oo+=B++. |
|. .E*%++ . |
| ..=O+= . |
| . +oB |
| o = * S |
| o + B o |
| . o + o |
| . o o |
| ..o |
+----[SHA256]-----+
密钥生成后会在当前目录下多出两个文件,id_rsa和id_rsa.pub,其中id_rsa是私钥(这个很重要,不能外泄),id_rsa.pub这个是公钥
root@hls-virtual-machine:~/.ssh# ls -l
-rw------- 1 root root 3389 11月 18 17:17 id_rsa
-rw-r--r-- 1 root root 750 11月 18 17:17 id_rsa.pub
-rw-r--r-- 1 root root 1340 11月 17 21:00 known_hosts
把公钥拷贝到需要登录的远程服务器或Linux系统上,这里可以使用ssh-copy-id自动完成,也可以手动追加秘钥到远程服务器。
3)追加秘钥到远程服务器:
方法一(推荐):ssh-copy-id -i ~/.ssh/id_rsa.pub [email protected]
root@hls-virtual-machine:~/.ssh# ssh-copy-id -i ~/.ssh/id_rsa.pub [email protected]
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub"
The authenticity of host '192.168.18.162 (192.168.18.162)' can't be established.
RSA key fingerprint is SHA256:KvaB294bFQV3q6BX76F4vWr8AL3MDFGHY0HmqP3ZWqo.
Are you sure you want to continue connecting (yes/no/[fingerprint])?
执行命令了会要求输入远程机器的密码,输入密码即可
注:ssh-copy-id默认端口是22,如果您的SSH端口不是22,也就是远程服务器端口修改成其他的了,那就要得加上 -p +端口
服务端多出了一个authorized_keys:已授权的客户端公钥
成功实现密钥免密登陆(也可以这样登录root@hls-virtual-machine:~/.ssh# ssh -i ./id_rsa [email protected])
方法二:手动追加
进入远程服务器需要SSH登录的用户的目录下,这里仍然用root用户,cd /root/.ssh,执行ls看看目录下是否有authorized_keys文件没有的话则执行以下命令创建:
touch authorized_keys
touch authorized_keys
并修改权限:chmod 600 /root/.ssh/authorized_keys
chmod 600 /root/.ssh/authorized_keys
在客户端上将公钥传到服务端:scp id_rsa.pub [email protected]:/root/.ssh
root@hls-virtual-machine:~/.ssh# scp id_rsa.pub [email protected]:/root/.ssh
id_rsa.pub
将内容追加到authorized_keys:cat /root/.ssh/id_rsa.pub >> /root/.ssh/authorized_keys (>> 表示追加内容 > 替换内容)
cat /root/.ssh/id_rsa.pub >> /root/.ssh/authorized_keys
ssh-keygen可用的参数选项有:
-a trials
在使用 -T 对 DH-GEX 候选素数进行安全筛选时需要执行的基本测试数量。
-B 显示指定的公钥/私钥文件的 bubblebabble 摘要。
-b bits
指定密钥长度。对于RSA密钥,最小要求768位,默认是2048位。DSA密钥必须恰好是1024位(FIPS 186-2 标准的要求)。
-C comment
提供一个新注释
-c 要求修改私钥和公钥文件中的注释。本选项只支持 RSA1 密钥。
程序将提示输入私钥文件名、密语(如果存在)、新注释。
-D reader
下载存储在智能卡 reader 里的 RSA 公钥。
-e 读取OpenSSH的私钥或公钥文件,并以 RFC 4716 SSH 公钥文件格式在 stdout 上显示出来。
该选项能够为多种商业版本的 SSH 输出密钥。
-F hostname
在 known_hosts 文件中搜索指定的 hostname ,并列出所有的匹配项。
这个选项主要用于查找散列过的主机名/ip地址,还可以和 -H 选项联用打印找到的公钥的散列值。
-f filename
指定密钥文件名。
-G output_file
为 DH-GEX 产生候选素数。这些素数必须在使用之前使用 -T 选项进行安全筛选。
-g 在使用 -r 打印指纹资源记录的时候使用通用的 DNS 格式。
-H 对 known_hosts 文件进行散列计算。这将把文件中的所有主机名/ip地址替换为相应的散列值。
原来文件的内容将会添加一个".old"后缀后保存。这些散列值只能被 ssh 和 sshd 使用。
这个选项不会修改已经经过散列的主机名/ip地址,因此可以在部分公钥已经散列过的文件上安全使用。
-i 读取未加密的SSH-2兼容的私钥/公钥文件,然后在 stdout 显示OpenSSH兼容的私钥/公钥。
该选项主要用于从多种商业版本的SSH中导入密钥。
-l 显示公钥文件的指纹数据。它也支持 RSA1 的私钥。
对于RSA和DSA密钥,将会寻找对应的公钥文件,然后显示其指纹数据。
-M memory
指定在生成 DH-GEXS 候选素数的时候最大内存用量(MB)。
-N new_passphrase
提供一个新的密语。
-P passphrase
提供(旧)密语。
-p 要求改变某私钥文件的密语而不重建私钥。程序将提示输入私钥文件名、原来的密语、以及两次输入新密语。
-q 安静模式。用于在 /etc/rc 中创建新密钥的时候。
-R hostname
从 known_hosts 文件中删除所有属于 hostname 的密钥。
这个选项主要用于删除经过散列的主机(参见 -H 选项)的密钥。
-r hostname
打印名为 hostname 的公钥文件的 SSHFP 指纹资源记录。
-S start
指定在生成 DH-GEX 候选模数时的起始点(16进制)。
-T output_file
测试 Diffie-Hellman group exchange 候选素数(由 -G 选项生成)的安全性。
-t type
指定要创建的密钥类型。可以使用:"rsa1"(SSH-1) "rsa"(SSH-2) "dsa"(SSH-2)
-U reader
把现存的RSA私钥上传到智能卡 reader
-v 详细模式。ssh-keygen 将会输出处理过程的详细调试信息。常用于调试模数的产生过程。
重复使用多个 -v 选项将会增加信息的详细程度(最大3次)。
-W generator
指定在为 DH-GEX 测试候选模数时想要使用的 generator
-y 读取OpenSSH专有格式的公钥文件,并将OpenSSH公钥显示在 stdout 上。
ssh-copy-id的参数有:
-i #指定密钥文件
-p #指定端口,默认端口号是22
-o
user@]hostname #用户名@主机名
-f: force mode -- copy keys without trying to check if they are already installed
-n: dry run -- no keys are actually copied
-h|-?: 显示帮助
scp是基于ssh的远程拷贝命令,也支持本地拷贝,甚至支持远程到远程的拷贝,scp由于基于ssh,所以其端口也是使用ssh的端口。其实,scp拷贝的实质是使用ssh连接到远程,并使用该连接来传输数据。另外,scp还非常不占资源,不会提高多少系统负荷,在这一点上,rsync远不及它。虽然 rsync比scp会快一点,但rsync是增量拷贝,要判断每个文件是否修改过,在小文件众多的情况下,判断次数非常多,导致rsync效率较差,而scp基本不影响系统正常使用。scp每次都是全量拷贝。
scp [-12BCpqrv] [-l limit] [-o ssh_option] [-P port] [[user@]host1:]src_file ... [[user@]host2:]dest_file
选项说明:
-1:使用ssh v1版本,这是默认使用协议版本
-2:使用ssh v2版本
-C:拷贝时先压缩,节省带宽
-l:limit:限制拷贝速度,Kbit/s,1Byte=8bit,所以"-l 800"表示的速率是100K/S
-o:ssh_option:指定ssh连接时的特殊选项,一般用不上。
-P:port:指定目标主机上ssh端口,大写的字母P,默认是22端口
-p:拷贝时保持源文件的mtime,atime,owner,group,privileges
-r:递归拷贝,用于拷贝目录。注意,scp拷贝遇到链接文件时,会拷贝链接的源文件内容填充到目标文件中(scp的本质就是填充而非拷贝)
-v:输出详细信息,可以用来调试或查看scp的详细过程,分析scp的机制
注意:scp拷贝是强制覆盖型拷贝,当有重名文件时,不会进行任何询问。
1)本地拷贝到本地(与cp类似):/路径/文件名-->/路径/文件名
[root@mjx ~]# scp ce.txt ce_bak.txt
2)本地到远程:/路径/文件名--> IP:/路径/文件名
#用户名一致可省略
[root@mjx ~]# scp ce.txt 192.168.18.163:/root/hh.txt
ce.txt 100% 334 81.4KB/s 00:00
#用户名不一致需指定用户名
[root@mjx ~]# scp ce.txt [email protected]
3)远程到本地:IP:/路径/文件名-->/路径/文件名
[root@mjx ~]# scp 192.168.18.163:/root/hh.txt ./ss.txt
4).远程路径1到远程路径2:IP1:/路径/文件名-->IP2/路径/文件名
[root@mjx ~]# scp 192.168.18.162:/root/ss.txt 192.168.18.163:/root/ss_bak.txt
使用-v 参数可以输出命令的执行过程
[root@mjx ~]# scp -v ss.txt 192.168.18.163:/root/gc.txt
执行输出过程:
# 首先输出本地要执行的命令
Executing: program /usr/bin/ssh host 192.168.18.163, user (unspecified), command scp -v -t /root/gc.txt
OpenSSH_7.4p1, OpenSSL 1.0.2k-fips 26 Jan 2017
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: /etc/ssh/ssh_config line 58: Applying options for *
# 从本地连接到目标主机
debug1: Connecting to 192.168.18.163 [192.168.18.163] port 22.
debug1: Connection established.
debug1: permanently_set_uid: 0/0
debug1: identity file /root/.ssh/id_rsa type 1
debug1: key_load_public: No such file or directory
debug1: identity file /root/.ssh/id_rsa-cert type -1
debug1: key_load_public: No such file or directory
debug1: identity file /root/.ssh/id_dsa type -1
debug1: key_load_public: No such file or directory
debug1: identity file /root/.ssh/id_dsa-cert type -1
debug1: key_load_public: No such file or directory
debug1: identity file /root/.ssh/id_ecdsa type -1
debug1: key_load_public: No such file or directory
debug1: identity file /root/.ssh/id_ecdsa-cert type -1
debug1: key_load_public: No such file or directory
debug1: identity file /root/.ssh/id_ed25519 type -1
debug1: key_load_public: No such file or directory
debug1: identity file /root/.ssh/id_ed25519-cert type -1
debug1: Enabling compatibility mode for protocol 2.0
debug1: Local version string SSH-2.0-OpenSSH_7.4
debug1: Remote protocol version 2.0, remote software version OpenSSH_8.2p1 Ubuntu-4ubuntu0.1
debug1: match: OpenSSH_8.2p1 Ubuntu-4ubuntu0.1 pat OpenSSH* compat 0x04000000
debug1: Authenticating to 192.168.18.163:22 as 'root'
debug1: SSH2_MSG_KEXINIT sent
debug1: SSH2_MSG_KEXINIT received
debug1: kex: algorithm: curve25519-sha256
debug1: kex: host key algorithm: rsa-sha2-512
debug1: kex: server->client cipher: [email protected] MAC: compression: none
debug1: kex: client->server cipher: [email protected] MAC: compression: none
debug1: kex: curve25519-sha256 need=64 dh_need=64
debug1: kex: curve25519-sha256 need=64 dh_need=64
debug1: expecting SSH2_MSG_KEX_ECDH_REPLY
debug1: Server host key: ssh-rsa SHA256:YKj0Tj2fzNIyMfitJkJmvPDe/Yxui9qlvYyONXrQhwU
debug1: Host '192.168.18.163' is known and matches the RSA host key.
debug1: Found key in /root/.ssh/known_hosts:5
debug1: rekey after 134217728 blocks
debug1: SSH2_MSG_NEWKEYS sent
debug1: expecting SSH2_MSG_NEWKEYS
debug1: SSH2_MSG_NEWKEYS received
debug1: rekey after 134217728 blocks
debug1: SSH2_MSG_EXT_INFO received
debug1: kex_input_ext_info: server-sig-algs=
debug1: SSH2_MSG_SERVICE_ACCEPT received
debug1: Authentications that can continue: publickey,password
debug1: Next authentication method: publickey
debug1: Offering RSA public key: /root/.ssh/id_rsa
debug1: Authentications that can continue: publickey,password
debug1: Trying private key: /root/.ssh/id_dsa
debug1: Trying private key: /root/.ssh/id_ecdsa
debug1: Trying private key: /root/.ssh/id_ed25519
# 要求验证本地和目标主机之间的连接
debug1: Next authentication method: password
[email protected]'s password:
debug1: Authentication succeeded (password).
Authenticated to 192.168.18.163 ([192.168.18.163]:22).
debug1: channel 0: new [client-session]
debug1: Requesting [email protected]
debug1: Entering interactive session.
debug1: pledge: network
debug1: client_input_global_request: rtype [email protected] want_reply 0
debug1: Sending environment.
debug1: Sending env LANG = en_US.UTF-8
#从本地拷贝源文件到目标主机上
debug1: Sending command: scp -v -t /root/gc.txt
Sending file modes: C0644 334 ss.txt
Sink: C0644 334 ss.txt
ss.txt 100% 334 65.5KB/s 00:00
debug1: client_input_channel_req: channel 0 rtype exit-status reply 0
debug1: channel 0: free: client-session, nchannels 1
debug1: fd 0 clearing O_NONBLOCK
debug1: fd 1 clearing O_NONBLOCK
Transferred: sent 2972, received 2944 bytes, in 0.3 seconds
Bytes per second: sent 9241.4, received 9154.3
# 关闭本地主机和目标主机的连接
debug1: Exit status 0
数字签名是一个带有密钥的消息摘要算法,这个密钥包括了公钥和私钥,用于验证数据完整性、认证数据来源和抗否认,遵循OSI参考模型、私钥签名和公钥验证。也是非对称加密算法和消息摘要算法的结合体,常见的数字签名算法主要有RSA、DSA、ECDSA三种。
RSA是目前计算机密码学中最经典算法,也是目前为止使用最广泛的数字签名算法,RSA数字签名算法的密钥实现与RSA的加密算法是一样的,算法的名称都叫RSA。密钥的产生和转换都是一样的,包括在售的所有SSL数字证书、代码签名证书、文档签名以及邮件签名大多都采用RSA算法进行加密。
RSA 数字签名算法主要包括MD和SHA两种算法,例如我们熟知的MD5和SHA-256即是这两种算法中的一类,具体如下表格分布
1)MD5算法
最常见的是我们熟知的MD5加密算法,MD5全称Message-Digest Algorithm 5(信息-摘要算法 5),目前比较普遍的Hash算法,是散列算法的基础原理,MD5的前身有MD2、MD3和MD4。MD5算法法是输入任意长度字符,输出固定长度128位的算法。经过程序流程,生成四个32位数据,最后联合起来成为一个128位Hash值,主要方式是通过求余、取余、调整长度、与链接变量进行循环运算进而得出结果。
2)SHA-1算法
SHA-1是由NIST NSA设计为同DSA一起使用的,SHA-1设计时基于和MD4相同原理,并且模仿了该算法,SHA-1抗穷举(brute-force)性更好,它产出160位的Hash值,对于非线性运算、移位和加法运算也与MD5类似。SHA-1也应用于包括TLS和SSL、PGP、SSH、S/MIME和IPsec等多种协议中,曾被视为是MD5的后继者。SHA-1的如今已经明确不具备安全性可言了。
在2016年1月1日后基于SHA-1签发的SSL和代码签名的X.509证书已不具备安全性可言,多个操作系统、浏览器都建议将基于SHA-1而签发的证书、代码签名替换至SHA-2的产品,但目前在Windows XP(官方已停更)操作系统上仍然只兼容基于SHA-1算法的SSL和代码签名产品。
就在2017年2月23日Google宣布实现了对SHA-1算法的碰撞破解,所以SHA-1算法已经正式被宣布为不安全的算法,主流厂商对自身产品及安全要求都提升至了SHA-2算法。
3)SHA-2算法
SHA-224、SHA-256、SHA-384和SHA-512并称为SHA-2,发布于2001年,目前比较广泛应用的SSL数字证书和代码签名证书签名算法均采用SHA-256算法,相较于SHA-1算法而言,至今SHA-2算法还未被破解,从某种意义上SHA-2延用了SHA-1算法,所以至少发文时间起是安全的。目前顶级CA和Google、苹果等公司都采用基于SHA-256算法作为SSL证书和代码签名证书的主流签名算法。
4)SHA-3算法
SHA-3算法正式发布于2015年,SHA-3并不是要取代SHA-2,因为SHA-2目前并没有出现明显的弱点。由于对MD5、SHA-0和SHA-1出现成功的破解,NIST感觉需要一个与之前算法不同的,可替换的加密Hash算法,也就是现在的 SHA-3。
DSA全称Digital Signature Algorithm,DSA只是一种算法,和RSA不同之处在于它不能用作加密和解密,也不能进行密钥交换,只用于签名,所以它比RSA要快很多,其安全性与RSA相比差不多。DSA的一个重要特点是两个素数公开,这样,当使用别人的p和q时,即使不知道私钥,你也能确认它们是否是随机产生的,还是作了手脚。RSA算法却做不到。
DSA的整个签名算法流程如下:
ECDSA是用于数字签名,是ECC与DSA的结合,整个签名过程与DSA类似,所不一样的是签名中采取的算法为ECC,最后签名出来的值也是分为r,s。而ECC(全称Elliptic Curves Cryptography)是一种椭圆曲线密码编码学。
ECDH每次用一个固定的DH key,导致不能向前保密(forward secrecy),所以一般都是用ECDHE(ephemeral)或其他版本的ECDH算法。ECDH则是基于ECC的DH( Diffie-Hellman)密钥交换算法。
ECC与RSA 相比,有以下的优点:
在 ssh-keygen 中,ECC 算法的相应参数是 “-t ecdsa”。可惜的是由于椭圆曲线算法只有在较新版本的 openssl 与 ssh-keygen 中才被支持,而无法得到普遍使用而去完全替代 RSA/DSA。不过由于椭圆曲线算法的优点,使其取代 RSA/DSA 而成为新一代通用的非对称加密算法成为可能,至少 SET 协议的制定者们已经把它作为下一代 SET 协议中缺省的公钥密码算法了。