详解 SSH
概述
SSH 全称 The Secure Shell protocol,它是应用层上的一种加密的网络传输协议,可在不安全的网络中为网络服务提供安全的传输环境,它是通过在网络中创建安全隧道来实现 SSH 客户端与服务器端之间的连接。SSH 协议最常见的用途是远程登录系统,人们通常使用 SSH 来传输命令行界面和远程执行命令,因此可以说它是我们使用最频繁的网络协议之一。
在设计上,SSH 是 telnet 和非安全 shell 的替代品,Telnet 和 Berkeley rlogin、rsh、rexec 等协议采用明文传输,使用不可靠的密码,容易遭到监听、嗅探和中间人攻击。SSH 旨在保证非安全网络环境(例如互联网)中信息加密完整可靠。
定义
SSH 协议先后定义在多个RFC文档中,以下列出了 SSH 协议相关的一些重要的 RFC。
RFC | 介绍 | 时间 |
---|---|---|
RFC 4250 | 协议号码 | 2006 年 01 月 |
RFC 4251 | 协议架构 | 2006 年 01 月 |
RFC 4252 | 身份验证 | 2006 年 01 月 |
RFC 4253 | SSH 传输层协议 | 2006 年 01 月 |
RFC 4254 | SSH 连接协议 | 2006 年 01 月 |
RFC 4255 | 使用 DNS 发布 SSH 密钥指纹 | 2006 年 01 月 |
RFC 4256 | SSH 的通用消息交换身份验证 | 2006 年 01 月 |
RFC 4335 | SSH 会话通道中断扩展 | 2006 年 01 月 |
RFC 4344 | SSH 传输层加密模式 | 2006 年 01 月 |
RFC 4716 | SSH 公钥文件格式 | 2006 年 11 月 |
RFC 4819 | 公钥子系统 | 2007 年 03 月 |
应用
SSH 协议除了最常见的登录远程系统外,还有多种其他的用途,归纳起来可以分为以下几类:
- 远程登录系统(SSH Clien)
- 安全的文件传输(SFTP)
- 远程设备管理和账号控制
- SSH 隧道
- 端口转发
- X11 连接
- 安全的身份验证
历史
1.x 版本
芬兰赫尔辛基理工大学的塔图·于勒宁发现自己学校存在嗅探密码的网络攻击,便于 1995 年编写了一套保护信息传输的程序,并称其为 “secure shell”,简称 SSH,设计目标是取代先前的 rlogin、Telnet、FTP和 rsh 等安全性不足的协议。 1995 年 7 月,于勒宁以免费软件的形式将其发布。程序很快流行起来,截至 1995 年底,SSH 的用户数已经达到两万,遍布五十个国家。
1995 年 12 月,于勒宁创立了 SSH 通信安全公司来继续开发和销售 SSH。SSH 的早期版本用到了很多自由软件,例如 GNU libgmp,但后来由 SSH 公司发布的版本逐渐变成了专有软件。
截至2000年,已经有两百万用户使用SSH。
OpenSSH 和 OSSH
1999 年,开发者们希望使用自由版本的 SSH,于是重新使用较旧的 1.2.12 版本,这也是最后一个采用开放源代码许可的版本。随后瑞典程序员 Björn Grönvall 基于这个版本开发了 OSSH。不久之后,OpenBSD 的开发者又在 Grönvall 版本的基础上进行了大量修改,形成了 OpenSSH,并于 OpenBSD 2.6 一起发行。从该版本开始,OpenSSH 又逐渐移植到了其他操作系统上面。
截至 2005 年,OpenSSH 是唯一一种最流行的 SSH 实现,而且成为了大量操作系统的默认组件,而 OSSH 已经过时。OpenSSH 仍在维护,而且已经支持 SSH-2 协议。从 7.6 版开始,OpenSSH 不再支持 SSH-1 协议。
2.x 版本
2006 年,SSH-2 协议成为了新的标准。与 SSH-1 相比,SSH-2 进行了一系列功能改进并增强了安全性,例如基于迪菲-赫尔曼密钥交换的加密和基于消息认证码的完整性检查。SSH-2 还支持通过单个 SSH 连接任意数量的 shell 会话。SSH-2 协议与 SSH-1 不兼容,由于更加流行,一些实现(例如 lsh 和 Dropbear)只支持 SSH-2 协议。
1.99 版
RFC 4253 规定支持 2.0 及以前版本 SSH 的 SSH 服务器应将其原始版本标为 “1.99”。“1.99” 并不是实际的软件版本号,而是为了表示向下兼容。
工作原理
基本架构
SSH 协议框架中最主要的部分是三个协议:
- 传输层协议(The Transport Layer Protocol):传输层协议提供服务器认证,数据机密性,信息完整性等的支持。
- 用户认证协议(The User Authentication Protocol):用户认证协议为服务器提供客户端的身份鉴别。
- 连接协议(The Connection Protocol):连接协议将加密的信息隧道复用成若干个逻辑通道,提供给更高层的应用协议使用。
他们的关系如下图:
如果放在整个网络模型中,大概就是以下这个样子:
同时还有为许多高层的网络安全应用协议提供扩展的支持。各种高层应用协议可以相对地独立于 SSH 基本体系之外,并依靠这个基本框架,通过连接协议使用 SSH 的安全机制。
工作过程
SSH 协议的实现是以 C/S 架构的模式工作的,也就是说 SSH 会话连接的建立都是通过 SSH 客户端连接到 SSH 服务端。SSH 客户端主导连接设置的过程,由 SSH 客户端发起 SSH 会话连接,并使用公钥验证 SSH 服务端的身份。在后续阶段 SSH 协议使用对称加密和散列算法来确保客户端和服务端之间数据交换的安全性和完整性。
下图大致画出了 SSH 协议工作过程:
流程包括以下三个阶段,分别对应着前文 SSH 基础架构中的三个协议过程:
传输层协议
握手过程
- TCP Connection:一旦 TCP 握手完成建立连接,客户端和服务端之间交换 ID 字符串。
- Algorithm Negotiation:算法协商,双方支持的密钥交换算法和压缩算法列表,用于在客户端和服务端之间协商出双方共同支持的算法。
- Key Exchange:密钥交换,服务器将向客户端进行身份验证,并生成服务器消息身份验证和密钥。
- End of key Exchange:协商交换完成,这将表明客户端和服务端双方后续将以协商的算法进行加解密和压缩。
用户认证协议
用户认证协议发生在传输层协议完成之后,客户端将包括认证方式、用户名等信息的消息通过会话密钥加密发送给服务端,用于验证客户端身份,目前支持一下三种的客户端身份认证:
- 密码验证:如果认证方式为密码认证,则客户端会发送密码消息用于验证客户端身份,该消息受传输层协议加密保护。知道帐号和密码,就可以登录到远程主机,并且所有传输的数据都会被 SSH 传输层协议加密。但是,可能会有别的服务器在冒充真正的服务器,但只要客户端校验主机公钥,在服务器私钥不泄露的前提下就能避免被“中间人”攻击。
- 密钥验证:如果认证方式为密钥验证,则客户端发送包含由客户端私钥签名的客户端公钥。当服务器收到此消息时,它会检查提供的密钥是否可以接受身份验证,如果可以,它会检查签名是否正确。具体说来,客户端必须为自己创建一对密钥,并把公钥放在需要访问的服务器上。客户端软件会向服务器发出请求,请求用你的私钥进行安全验证并发送使用私钥对会话 ID 等信息的签名。服务器收到请求之后,先在你在该服务器的用户根目录下寻找你的公钥,然后把它和你发送过来的公钥进行比较,并用公钥检验签名是否正确。如果两个密钥一致,且签名正确,服务器就认为用户登录成功。
- 主机验证:身份验证是在客户端的主机上执行的,而不是客户端本身。因此,支持多个客户端的主机将为其所有客户端提供身份验证。此方法的工作原理是让客户端发送使用客户端主机的私钥创建的签名。因此,SSH 服务器不是直接验证用户的身份,而是验证客户端主机的身份。
补充:在服务端看来,SSH 也提供安全验证
- 服务器将自己的公钥分发给相关的客户端,并将密钥交换过程中的公开信息与协商密钥的哈希值的签名发送给客户端,客户端将获取的服务器公钥计算指纹并与其他安全信道获得的公钥指纹相比对并验证主机签名。
- 存在一个密钥认证中心,所有提供服务的主机都将自己的公钥提交给认证中心,公钥认证中心给服务端颁发证书,而任何作为客户端的主机则只要保存一份认证中心的公钥就可以了。在这种模式下,服务器会发送认证中心提供给主机的证书与主机对密钥交换过程中公开信息的签名。客户端只需要验证证书的有效性并验证签名。
连接协议
连接协议发生在连接建立的最后一个阶段,它允许将加密的信息隧道复用成若干个逻辑通道,提供给更高层的应用协议使用,同时还有为许多高层的网络安全应用协议提供扩展的支持,各种高层应用协议可以相对地独立于 SSH 协议体系之外,并依靠这个基本框架,通过连接协议使用 SSH 的安全机制。例如:
- session:程序的远程执行。该程序可能是一个shell、一个应用程序,如文件传输或电子邮件,一个系统命令或一些内置子系统。一旦会话通道被打开,后续请求将用于启动远程程序。
- X11:这指的是X Window系统,一个计算机软件系统和网络协议,为联网计算机提供图形用户界面(GUI)。X允许应用程序在网络服务器上运行,但显示在桌面机器上。
- 远程端口转发和本地端口转发。
- 文件传输。
SSH 协议常见应用场景解析
上文提到,SSH 协议除了最常见的登录远程系统外,还有多种其他的用途,下面主要讲解 SSH 协议两种其他常见的使用场景。
SFTP
说到 SFTP(default port is 21) 就不得不提 FTP,前面说到,使用 SSH 协议的远程登录就是为零代替不安全的 telnet 的,同样的,SFTP 也就是为了代替不安全的 FTP 的。
FTP 客户端是一个软件应用程序,允许登录运行 FTP 服务器软件的计算机。一旦用户连接到服务器并使用密码进行身份验证,用户就可以从服务器计算机传输文件和文件夹。客户端功能嵌入在大多数常见的网络浏览器中,但也可以作为大多数常见操作系统的单独专用软件应用程序使用。FTP 协议未加密,并透明地传输密码和数据。工具广泛可用于从网络中捕获用户名和密码。这被称为密码嗅探,在 20 世纪 90 年代中期就已经是一种常见的攻击。
SFTP 协议和 SSH 几乎在所有新应用程序中都取代了 FTP。FTP只能与不支持 SFTP 的遗留系统一起使用。使用 FTP时,通常不可能在受监管的行业中实现合规性。使用 SFTP 替代品,也很容易实现文件传输自动化。SFTP 支持使用加密密钥、SSH 密钥进行身份验证。这使得自动化变得非常容易。SFTP 协议还可以跨防火墙和网络地址转换(NAT)自动工作,无需任何特殊配置。
SSH Tunneling
什么是 SSH Tunneling
SSH 隧道是一种通过加密的 SSH 连接传输任意网络数据的方法。它可用于将加密添加到以及停止维护的应用程序中。它还可用于实现 VPN(虚拟专用网络)和跨防火墙访问内联网服务。
SSH 是在不受信任的网络上进行安全远程登录和文件传输的标准。它还提供了一种使用端口转发保护任何给定应用程序的数据流量的方法,基本上通过 SSH 隧道转发任何 TCP/IP 端口,这意味着应用程序数据流量被引导到加密的 SSH 连接内流动,因此在传输过程中不会被窃听或拦截。SSH 隧道可以为原生不支持加密的已经停止维护的应用程序添加网络安全。
上图显示了 SSH 隧道的简化概述。通过不受信任的网络在 SSH 客户端和 SSH 服务器之间建立安全连接。此 SSH 连接是加密的,保护机密性和完整性,并对通信方进行身份验证。
应用程序使用 SSH 连接连接到应用程序服务器。启用隧道后,应用程序会连接到 SSH 客户端监听的本地主机上的端口。然后,SSH 客户端通过其加密隧道将应用程序转发到服务器。然后,服务器连接到实际的应用程序服务器-通常与SSH 服务器在同一台机器或同一数据中心。因此,应用程序通信是安全的,而无需修改应用程序或最终用户工作流程。
如何使用 SSH Tunneling
通常来说,SSH Tunneling 缺点是,任何能够登录服务器的用户都可以启用端口转发,这被内部 IT 人员广泛利用,在云中登录他们的家庭机器或服务器,将端口从服务器转发回企业内部网到他们的工作机器或合适的服务器。黑客和恶意软件同样可以用它来将后门留在内部网络中,它还可用于通过多个允许不受控制的隧道的设备反弹攻击来隐藏攻击者的踪迹。
这里是一个 SSH Tunneling 的 使用配置,SSH Tunneling 通常与 SSH 密钥和公钥身份验证一起使用,以实现过程的完全自动化。
SSH Tunneling 对企业的好处
SSH 隧道在许多使用大型机系统作为应用程序后端的公司环境中被广泛使用。在这些环境中,应用程序本身对安全性的原生支持可能非常有限。通过使用隧道,无需修改应用程序即可实现对 SOX、HIPAA、PCI-DSS 和其他标准的合规性。
在许多情况下,企业里的这些应用程序和应用程序服务器更改的代价非常大,甚至某些程序的源代码可能不可用,供应商可能不再存在,产品可能没有支持,或者开发团队可能不再存在。添加安全包装器,如 SSH 隧道,为此类应用程序增加了安全性提供了一种具有成本效益和实用的方法。例如,为了安全起效,整个全国范围内的 ATM 网络都使用隧道运行。
SSH 协议报文分析
最后,我们对 SSH 协议的报文进行具体的分析,在分析具体的报文之前,先来明确两个概念:
- 会话密钥 key:key 是通过客户端和服务端之间通过诸如 D-H 算法协商出来的,是在 SSH 会话数据传输过程中对称加密使用的密钥。
- 公钥 pub key:pub key 称为服务主机密钥 server_host_key,用于 SSH-TRANS 传输协议进行服务器验证,说简单点就是在身份验证阶段客户端去验证服务器用的。
报文分析
下面以下图中的例子来分析 SSH 协议的报文
TCP 三次握手
上图中,1 - 3 报文是 TCP 的三次握手,因为比较基础,也不属于本篇文章讨论的范畴,因此对这一部分不做分析。
SSH 协议版本协商
上图中 4 和 6 即是 SSH 协议版本协商过程
No | 描述 | 解释 |
---|---|---|
6 | SSH 协议版本协商 | 服务器将自己的 SSH 协议版本发送到客户端,格式为:SSH-protoversion(版本号)-softwareversion(自定义) SP(空格一个,可选) comments(注释,可选) CR(回车) LF(换行) |
4 | SSH 协议版本协商 | 客户端将自己的 SSH 协议版本发送到服务器,格式为:SSH-protoversion(版本号)-softwareversion(自定义) SP(空格一个,可选) comments(注释,可选) CR(回车) LF(换行) |
这一步其实很简单,总结下来就是发送了一个格式为 SSH-protoversion-softwareversion SP comments CR LF 的字节流。
SSH 协议算法协商
上图中的 8 - 16 就是 SSH 协议算法协商过程,该过程从客户端和服务器相互发出Key Exchange Init请求开始,主要是告诉对方自己支持的相关加密算法列表、MAC算法列表等。最后协商成功后,将会生成对称加密的会话密钥 key 和一个会话 ID。
需要注意的是,这里生成的是后续用于对称加密的会话密钥 key,不要跟公钥弄混淆了,至于两者的区别,在本小节一开头就已经做了解释,公钥是给客户端验证服务器身份用的。
与此同时,在这一步公钥会从服务器传送到客户端,完成密钥交换的过程。
再来说一下会话密钥,这里的会话密钥是通过 D - H 算法计算出来的,不会在网络上传输,其破解的难度取决于离散对数的破解难度,几乎不会被破解。
下面将具体分析一下 Key Exchange Init 报文包
关键字 | 解释 |
---|---|
kex_algorithms | 密钥交换算法,里面即包含使用的 D - H 算法,用于生成会话密钥 |
server_host_key_algorithms | 服务器主机密钥算法,可以采用 ssh-rsa,ssh-dss,ecdsa-sha2-nistp256,有公钥和私钥的说法,公钥即我们上面讲到的 pub key。关于私钥的概念,可以参考 understanding public key private key concepts |
encryption_algorithms_client_to_server | 对称加密算法,常用的有 aes128-cbc,3des-cbc |
mac_algorithms_client_to_server | MAC 算法,主要用于保证数据完整性 |
compression_algorithms_client_to_server | 压缩算法 |
认证阶段
最后,上图中的 18 - 20 就是认证阶段
基于账号和口令的验证方式
客户端将自己的用户名 + 密码用上面生成的会话密钥 key 进行加密之后传送到服务器端进行验证,服务器端验证通过,则响应成功,否则在进行有限次(推荐是20次)重新认证。注意,用户名和密码是采用上面算法协商阶段生成的会话密钥 key 进行加密的,包括后面的连接会话阶段所传送的数据都是,不要认为是采用服务器的 pub key 加密的。
基于公钥和私钥的验证方式
这种方式也称为免密登录。简单地说,就是客户端自己生成公钥私钥(通常采用 ssh-keygen 程序生成),然后将公钥以某种方式(通常是手动添加)保存到服务器 ~/.ssh/authorized_keys 文件中,以后服务器都会接受客户端传过来的经过会话密钥加密过的公钥,然后解密得到公钥之后和本地的公钥签名是否一样,如果是,则允许登录。
Reference
https://en.wikipedia.org/wiki/Secure_Shell
https://www.ssh.com/academy/ssh
(全文完)