一文读懂系列:结合抓包分析,详解SSH协议通信原理
SSH协议通过建立加密通道来提供安全的远程访问、文件传输和执行远程命令等操作。接下来我们就通过具体示例和抓包分析,让大家清楚地了解SSH协议的神秘面纱!如有更多疑问,欢迎讨论区留言讨论~
1. SSH简介
SSH(Secure Shell)协议是一种用于在不安全的网络上提供安全通信的网络协议。
SSH客户端和服务器应用程序可广泛用于大多数操作系统。它已成为远程登录和X隧道的首选方法,并迅速成为嵌入式系统之外加密技术最普遍的应用之一。
最初的版本SSHv1侧重于提供安全的远程登录设施,以取代Telnet和其他不提供安全的远程登录方案。新版本SSHv2修复了原始方案中的许多安全漏洞。相关标准文档可以参阅RFC 4250
至RFC 4256
。
2. SSH协议栈介绍
SSH协议主要由三个子协议组成:传输层协议、用户认证协议和连接协议。
2.1. 传输协议
传输协议负责建立安全的通道,确保数据在传输过程中的机密性和完整性。它使用公钥加密算法(如RSA、DSA等)进行身份验证,并通过密钥交换算法(如Diffie-Hellman)生成共享会话密钥来保护会话数据。
在SSH客户端第一次连接某服务器时,我们会注意到上图中的连接提示。这其实就是客户端在通过host key验证服务器身份,确保其连接的是正确的服务器,而不是中间人攻击者。
$ ls -lht ~/.ssh
total 32
-rw------- 1 me staff 1.6K 11 7 22:54 known_hosts
-rw------- 1 me staff 1.7K 11 8 2015 github_rsa
-rw-r--r-- 1 me staff 405B 11 8 2015 github_rsa.pub
客户端将这个密钥(host key)存储起来,以便将来连接时进行验证,如果服务器发送过来的host key与客户端本地存储的一致,将不再弹出连接确认提示。
此外,传输协议还可能提供数据压缩功能,以提高传输效率。
2.2. 用户认证协议
用户认证协议运行在传输协议之上,用于验证客户端用户的合法性。SSH支持多种认证方式,包括公钥认证、密码认证和基于主机的认证。
在公钥认证中,客户端使用自己的私钥对消息进行签名,服务器则使用客户端提供的公钥验证签名的有效性。密码认证则涉及客户端发送明文密码,由服务器进行验证。
2.3. 连接协议
连接协议基于传输层和用户认证协议提供的安全隧道,将多个逻辑通道复用在一起。这些通道可以用于不同的目的,如安全的交互式shell会话、TCP端口转发和X11连接。
每个通道都有唯一的编号,并且支持流控制,以确保数据按顺序传输。当一个通道关闭时,不会影响其他通道的正常工作。
3. 工作原理
SSH交互过程可分为5个阶段:
- 版本协商:SSH支持SSHv1、SSHv2两个版本,双方通过协商确定本次会话使用的版本;
- 算法协商:SSH支持多种密码算法,双方会根据各自支持的算法协商出本次会话使用的密码算法;
- 密钥交换:通过密钥交换算法生成会话密钥,用于后续加密通信;
- 用户认证:SSH客户端向服务器发起认证请求服务器对登录用户进行认证;
- 会话交互:用户认证通过后,双方便可以开始通信。
以上5个阶段与上一章节介绍的协议栈关系可以用如下一张简图表示:
接下来我们以下面的客户端和服务器进行SSH交互为例,结合抓包进行分析。通信双方的信息如下:
-
客户端:10.211.55.2,OpenSSH 8.6
-
服务器:10.211.55.7,OpenSSH 9.4
在本地计算机上打开CMD窗,通过执行命令ssh root10.211.55.7
启动SSH客户端并连接到服务器,服务器SSH端口默认是22。
3.1. 版本协商
版本协商时客户端和服务器会交换各自支持的SSH协议版本信息。
客户端会首先发送一个包含其支持的SSH协议版本的消息到SSH服务器。消息格式为“SSH-2.0-clientname/version”
这样的消息,其中“clientname/version”
代表客户端的名称和版本信息。如下图:SSH-2.0-OpenSSH_8.6
收到此消息后,SSH服务器将回应一个相同格式的消息(如下图的SSH-2.0-OpenSSH_9.4p1 Debian-1
),表明服务器支持的SSH协议版本。
随后,客户端和服务端会基于它们都支持的最高协议版本进行后续的密钥交换和认证过程。
3.2. 算法协商
客户端和服务器分别发出Key Exchange Init
请求,告诉对方自己支持的相关加密算法列表、MAC算法列表和压缩算法。
如果对消息认证码MAC算法原理感兴趣可以参阅博主前期文章《图解 | 消息认证码(MAC)到底解决了什么问题?还有什么问题是它解决不了的?》。
算法协商过程比较简单,先从客户端支持的算法列表中取出第一个算法,服务器在自身的算法列表中查找,若匹配上相同的算法,则协商成功,接着按以上流程协商出下一种算法。否则继续从客户端的该种算法列表中取出下一个算法,在服务器的算法列表中匹配,直到匹配成功。
3.3. 密钥交换
双方使用Diffie-Hellman密钥交换算法生成共享会话密钥,通过运用数学理论可巧妙地实现不直接传递会话密钥的密钥交换,避免了在不安全通道传送会话密钥。双方协商得到的会话密钥用于加密后续通信,即使通信被截获,攻击者在没有会话密钥的前提下也无法解密内容。
下图中的12、13两个数据包即通过DH密钥交换算法协商出了会话密钥。
若对DH密钥交换(也称密钥协商)算法原理感兴趣,可能参阅博主前期文章《一文读懂密钥交换(DH、ECDH)算法(附密码国标)》,本文将不再展开介绍DH密钥交换的具体细节。
注意观察第13个数据包,服务端端会回复一个New Keys
包,表明服务端可以使用会话密钥加密消息了。
紧接着客户端回复服务端的New Keys
包,用于表明双方已经完成构建了一个加密通道,可以使用会话密钥来加密通信了。
密钥交换完成后,后续所有报文交互(用户认证、会话请求、会话交互)都会被会话密钥加密。
3.4. 用户认证
服务器向客户端展示其公钥,客户端验证该公钥是否合法(通常通过预存的已知主机列表):
- 如果是密码认证,系统会提示输入密码;
- 如果是公钥认证,客户端会自动使用本地存储的私钥对数据进行签名,并将签名发送给服务器。密钥存储在
~/.ssh/id_rsa
文件中,客户端在执行连接时可执行命令ssh user@remote_server_ip -i ~/.ssh/id_rsa
。
如果验证通过,服务器返回SSH_MSG_USERAUTH_SUCCESS
消息。
比如,典型的服务器认证为密码认证,具体流程如下图所示:
但是,这种认证方式存在中间人攻击的风险,如果有人截获了SSH客户端的登录请求后,冒充SSH服务器将伪造的公钥发送给SSH客户端,就可以获取到用户的登录密码。所以,在首次登录SSH服务器时,SSH客户端上会提示公钥指纹(host key),并询问用户是否确认登录。
从第15个数据包之后就开始了加密通信,已经无法看到SSH的认证阶段、会话请求和会话交互的明文数据包。
3.5. 会话交互
认证成功后,客户端和服务器创建多个逻辑通道,用于执行不同的任务,如shell会话、文件传输等。
4. 参考资料
本文写作过程中参考了以下技术文献,如果大家对SSH协议的更多内容细节感兴趣,可以关注博主公众号,并回复”20241109“获取如下资料包。
- RFC 4251-4254
- Cryptography, Network and Security Principles and Practice.pdf
- SSH 5.1.4.2 版本发布.pdf
- Computer Networking Principles, Protocols and Practice.pdf