SSH原理与配置

什么是SSH?

SSH(Secure Shell)是一种用于在不安全的网络上安全地访问远程计算机的协议。它提供了强大的身份验证和加密功能,确保数据在传输过程中不被窃听、篡改或伪造。SSH 广泛用于远程登录、命令执行、文件传输和端口转发等场景。

为什么需要SSH?

首先思考为什么需要 SSH?

传统的明文数据传输,内容容易被截获。在通信中出于保护数据安全的目的,一般的技术方案是对数据进行加密,常见的加密算法根据不同的密钥管理方式分为对称加密和非对称加密,前者加解密密钥相同,后者分为公钥和私钥。

对称加密的流程为:

  • 密钥生成:生成一个对称密钥
  • 加密:发送方使用对称密钥对明文数据进行加密,生成密文
  • 传输:将密文传输给接收方
  • 解密:接收方使用相同的对称密钥对密文解密,恢复出明文数据

对称加密由于加解和解密使用的是同一个密钥算法,故而在加解密的过程中速度比较快,适合于数据量比较大的加解密。对称加密的主要有优点就是算法公开、计算量小、加密速度快、加密效率高;但是它也存在强大的缺点,缺点就是密钥协商过程中,一旦密钥泄露,别人可以获取到密钥,这样也能对密文进行解密。另外,每对用户每次使用对称加密算法时,都需要使用其他人不知道的独一密钥,这会使得收、发双方所拥有的钥匙数量巨大,密钥管理成为双方的负担。常见的对称加密算法有:DES(Data Encryption Standard)、AES(Advanced Encryption Standard)、3DES(Triple DES)、Blowfish 和 RC2等。

非对称加密的流程为:

  • 密钥生成:生成一对密钥,公钥和私钥
  • 公钥分发:将公钥发给通信方
  • 加密:发送方使用接收方的公钥对明文数据进行加密,生成密文
  • 传输:将密文传输给接收方
  • 解密:接收方使用自己的私钥对密文进行解密,恢复出明文数据

非对称加密的特征是算法强度复杂、安全性依赖于算法与密钥但是由于其算法复杂,而使得加密解密速度没有对称加密解密的速度快。其密钥管理相对简单,提供了数字签名(私钥加密公钥解密)和身份认证功能,确保数据的完整性和真实性。常见的非对称加密算法有:RSA(Rivest-Shamir-Adleman)、ECC(Elliptic Curve Cryptography)和 DSA(Digital Signature Algorithm)等。

经过上述分析,如果使用对称密码算法,发送方和接收方如何协商会话密钥是一个棘手的问题,密钥一旦被泄露那么整个会话就不再安全。如果使用非对称密码算法,可以避免密钥管理困难性,但是接收方公钥的真实性无法保证,因为攻击者可以进行中途拦截,将公钥替换为自己的公钥,这样会话数据就能被轻松获取,这就是所谓的中间人攻击。

那么关键点就在于确认接收方公钥的真实性。

在HTTPS的TLS/SSL握手中,客户端通过CA签发的数字证书来认证服务端公钥真实性,因为CA是受信任的第三方机构,其通过严格的信任链机制来确保证书的合法性和安全性。并且考虑到密码算法效率,非对称密码算法用于密钥交换,对称密码算法用于数据信息加密。

SSH和SSL都是网络安全协议,通过加密和认证提升两台设备间传输数据的安全性。但SSH和SSL的生效方式和服务目标存在差异。SSH在两台设备间创建安全隧道,使这两台设备间可以安全地发送命令、传输数据等。例如,客户端通过SSH远程登录到一台服务器上,就可以安全地远程管理这台服务器,在服务器上执行想要的命令。SSL则是使用SSL证书保证两台设备间安全地传输数据,而不是像SSH那样可以执行命令。例如,用户通过浏览器访问某安装了SSL证书且启用了HTTPS的服务器,浏览器和服务器之间可以安全地传输数据。

SSH工作流程

为建立安全的SSH通道,SSH服务端和客户端需要先建立TCP连接,然后协商使用的版本号和各类算法,生成会话密钥用于后续的对称加密,在完成用户认证后,双方即可建立会话进行数据交互,工作流程如下:

  • TCP连接建立:SSH服务器在指定端口监听连接请求,客户端向对应端口发起连接请求后,双方进行TCP三次握手
  • 版本协商:SSH服务器和客户端通过协商确定最终使用的SSH版本号。具体的,服务器通过建立的TCP连接向客户端发送支持的SSH版本信息;客户端收到后根据自身支持的SSH版本决定使用的版本号,并将版本号发送给服务器,服务器判断自身是否支持,确定版本协商是否成功。
  • 算法协商:服务器和客户端分别向对方发送自己支持的密码学套件,协商使用的算法。
  • 密钥交换:客户端和服务器根据协商好的密钥交换算法进行密钥交换
  • 用户认证:客户端向服务器发送用户认证请求,服务器验证用户身份
  • 会话请求:认证通过后,客户端向服务器发送会话请求,请求服务器提供某种类型的服务,服务器根据请求进行回应
  • 会话交互:会话建立后,服务器和客户端在该会话上进行数据信息的交互,发送的数据由会话密钥进行加密。

SSH客户端向SSH服务器发起认证请求,SSH服务器对SSH客户端进行认证,有几种常见的认证方法:基于口令的认证、基于密钥的认证以及基于Kerberos的认证。

  • 基于口令的认证:客户端通过用户名和密码的方式进行认证,加密后的用户名和密码发送给服务器,服务器解密后与本地保存的用户名和密码进行比对,并向客户端返回认证成功或失败的消息。这种认证方式比较简单,每次登录都需要输入用户名和密码。
  • 基于密钥的认证:客户端使用自己的私钥对消息进行签名,服务器使用客户端公钥验证签名。和SSL不同,SSH客户端生成的公钥对无法通过CA公证,需要客户端手动将公钥添加至服务器的authorized key中。
    • 服务器收到认证请求后,会生成随机数R,并使用客户端公钥加密R,并将加密信息发送给客户端;
    • 客户端收到加密信息后,使用私钥解密获得R,客户端使用哈希算法对随机数R和会话密钥生成摘要Digest1,发送给服务器;
    • 服务器对R和会话密钥使用相同的哈希算法生成摘要Digest2,比较Digest1和Digest2,如果相同则完成认证过程。
  • 基于Kerberos的认证:客户端从Kerberos认证服务器获取票据,使用该票据向服务器请求访问,服务器认证票据的有效性。

SSH实践

常用命令及配置

1、连接到远程服务器

ssh username@hostname
ssh -p port_number username@hostname

2、生成SSH密钥对

ssh-keygen -t rsa -b 2048 -f ~/.ssh/id_rsa -C 'user@example.com'

各参数含义如下:

  • -t:指定密钥类型
  • -b:指定密钥长度
  • -f:指定密钥文件的保存路径
  • -C:添加注释,用户标识密钥的用途或所有者

不指定路径时,密钥默认保存在~/.ssh目录下,常见的密钥文件包括:

  • id_rsa 和 id_rsa.pub:RSA 密钥对
  • id_ecdsa 和 id_ecdsa.pub:ECDSA 密钥对
  • id_ed25519 和 id_ed25519.pub:Ed25519 密钥对

3、将公钥复制到远程服务器

将 ~/.ssh/id_rsa.pub 复制到远程服务器的 ~/.ssh/authorized_keys 文件中

ssh-copy-id username@hostname

4、指定特定的私钥文件

ssh -i /path/to/private_key username@hostname

5、启动ssh-agent

ssh-agent 是一个用于管理 SSH 私钥的代理程序。通过使用 SSH 代理,用户可以在会话期间缓存私钥的解密信息,避免频繁输入密码短语。使用不同的密钥连接到不同的主机时,需要要手动指定对应的密钥,而ssh代理可以自动帮助我们选择对应的密钥进行认证。(注意:ssh-agent,就要求repo使用的协议是ssh,而不是http)

运行 ssh agent 以后,会加载默认的私钥。如果有多个密钥,则需要在 ~/.ssh/config 中进行配置。

ssh-agent $SHELL
eval  '$(ssh-agent -s)'

6、添加私钥到ssh-agent

ssh-add 用于手动将私钥添加到 ssh-agent 中。

ssh-add ~/.ssh/id_rsa

7、从远程主机获取公钥

ssh-keyscan -p port_number -t type -f file hostname

各参数含义如下:

  • -p port:指定 SSH 服务器的端口号(默认是 22)。
  • -t type:指定要获取的密钥类型(如 rsa、dsa、ecdsa、ed25519)。
  • -f file:从文件中读取主机列表进行扫描。

8、为不同主机设置特定选项

客户端配置文件为~/.ssh/config,实例配置如下:

# 全局配置
Host *
    ForwardAgent yes
    ForwardX11 yes
    ServerAliveInterval 60

# 针对特定主机的配置
Host myserver
    HostName example.com
    User myuser
    Port 2222
    IdentityFile ~/.ssh/id_rsa
    Compression yes

Host another_server
    HostName another.example.com
    User anotheruser
    IdentityFile ~/.ssh/id_ed25519

常用配置选项:

  • Host:定义主机别名或通配符(如 * 表示所有主机)。
  • HostName:实际的主机名或 IP 地址。
  • User:默认的用户名。
  • Port:SSH 服务器的端口号。
  • IdentityFile:用于认证的私钥文件。
  • ForwardAgent:是否启用代理转发。
  • ForwardX11:是否启用 X11 转发。
  • ServerAliveInterval:发送保持活跃消息的间隔时间(以秒为单位)。
  • Compression:是否启用数据压缩。

9、保存已知的远程主机公钥信息

用于防止中间人攻击。当客户端首次连接到一个新的 SSH 服务器时,服务器会提供其公钥,会提示用户确认并将其公钥添加到已知主机文件中。以后每次连接到该主机时,客户端会检查 known_hosts 文件中存储的公钥信息,以验证远程主机的身份。如果公钥匹配,连接继续;如果不匹配,客户端会发出警告,提示可能存在安全风险。

know_hosts文件中的每一行包含一个已知主机的公钥信息,格式为:

hostname,ip_address key_type key

也可以手动添加公钥至know_host文件,例如使用ssh-keyscan命令

ssh-keyscan example.com >> ~/.ssh/known_hosts

10、测试连接是否正常

ssh -T git@hostname

SSH寻找私钥流程

1、根据命令行参数指定的私钥文件

如果使用了-i选项指定了私钥文件,那么客户端会根据该文件进行身份认证

2、检查SSH配置文件

如果在命令行参数没有指定私钥文件,客户端会检查配置文件 ~/.ssh/config,获取对应主机使用的私钥

3、使用默认私钥文件

如果没有在命令行参数、配置文件中指定私钥文件,SSH 客户端会尝试使用默认的私钥文件。这些文件通常位于用户的 ~/.ssh/ 目录下,获取默认公私钥文件。

  • ~/.ssh/id_rsa:RSA 私钥
  • ~/.ssh/id_dsa:DSA 私钥
  • ~/.ssh/id_ecdsa:ECDSA 私钥
  • ~/.ssh/id_ed25519:Ed25519 私钥

4、询问SSH代理

如果没有找到合适的私钥文件,SSH 客户端会询问正在运行的 SSH 代理(ssh-agent)是否有可用的私钥。

版权声明:本博客所有文章除特别声明外,均采用 CC BY 4.0许可协议,转载请注明出处
本文链接:https://blog.redamancy.tech/technique/47