SSH代理介绍

本文介绍 SSH、SSH 代理和 ProxyJump。

引言

SSH(Secure Shel安全外壳)广泛用于安全地连接到远程服务器。保护连接的最常用方法是使用密码。这种方法的缺陷在于,有时密码是可预测的且很弱,因此很容易猜到。另一个缺点是密码复杂性的限制。尽管密码在通过网络传输时是加密的,但与其他身份验证方法相比,使用自动脚本的暴力破解技术可以解密正常长度的密码。SSH 提供了一种更好的安全认证方式。SSH 代理消除了通过密码进行的身份验证。本文介绍 SSH 代理的工作原理、它的安全风险以及如何缓解这些风险。

背景

通过 SSH 连接

第一次连接到远程服务器时,系统会提示确定远程服务器的真实性。$ ssh [-p] [email protected]其中 -p 是服务器的端口号,可选的。如果输入 yes,服务器的公钥将添加到名为“已知主机known hosts”的文件中。即计算机将服务器识别为真实的。因此,下次尝试建立与同一台服务器的连接时,不会再次提示证明其真实性。这种机制称为 TOFU(首次使用时信任),客户端使用它来建立与尚未受信任的服务器的连接。当客户端第一次成功建立连接时,该服务器的身份将存储在客户端的本地信任数据库中。接下来,输入服务器的密码。这样就成功地连接到了远程服务器。

指纹是必要的,因为它们是连接的服务器的身份。现在假设网络外部有人拦截SSH 连接并将其路由到不同的 IP 地址,你会马上知道该活动,因为必须对该 IP 进行身份验证。看几个场景。

场景 1:尝试与之前使用“ssh [email protected]”进行身份验证的服务器建立连接。未知的攻击者控制了连接并更改了提供给 ssh 的 IP 地址。假设 IP 是 127.1.2.3,实际上将指令更改为“ssh [email protected]”。因为你没有预料到会受到攻击,所以你假设自己的机器不会要求服务器进行身份验证,因为它已经是受信任的。相反,系统会再次要求你进行身份验证,但这次是针对攻击者的服务器。这样你就知道有人在窃听。场景 2:当攻击者进入你的文件系统,更改你的受信任服务器的指纹时。当尝试连接到该服务器时,ssh 会抛出一条警告,指出“远程主机标识已更改”。场景 1 假设服务器使用 TOFU 建立的认证是真实的,客户端完全信任服务器提供的标识。但是你怎么知道提供的服务器的身份是合法的呢?这是 TOFU 失败的地方,不利于安全。场景 3:你第一次尝试在客户端和服务器之间建立连接。如果客户端的连接被暴露,攻击者可以渗透它,然后将其重新路由到另一台机器。该机器仍然通过提供其公钥来响应,客户端的计算机要求用户进行身份验证。但用户并不总是做出正确的决定。TOFU 假设攻击者在初始连接期间不存在,很危险。

SSH 和密钥

SSH 本身是安全的,但如果密码泄露或容易猜到,那么很容易受到来自外部的攻击。因此,一个解决方案是根本不使用密码,而是使用密钥。密钥是连接到服务器的一种安全方式,始终成对生成。密钥对由公钥和私钥组成。密钥对是数学关联的,使用公钥加密的数据只能由拥有相应私钥的人解密。公钥存储在远程服务器上,而私钥存储在客户端上。因此,当需要连接到服务器时,只需使用私钥进行身份验证,就会自动登录。但在后台,该过程:

客户端将密钥对 ID 发送到服务器。

服务器检查其信任数据库(authorized_key 文件)以找到与给定 ID 匹配的公钥。

找到成功的匹配后,服务器会生成一个唯一的随机挑战(如随机数),使用其公钥对其进行加密并将其发送回客户端。

如果客户端拥有相应的私钥,它能够解密该质询。

另一个称为会话密钥的密钥由客户端和服务器共享以加密通信。

客户端将解密的质询与会话密钥相结合以生成一个值。该值被散列并作为加密挑战的答案发送回服务器。

服务器对通过组合会话密钥和原始解密质询生成的值进行哈希处理。如果两个哈希值匹配,则证明客户端拥有相应的私钥,因此客户端通过了身份验证。

要生成一对密钥,使用 ssh-keygen。$ ssh-keygen

系统会立即提示你输入密钥的位置和密码。如果不指定位置,则使用默认位置。在上述情况下,默认位置是 Users/user/.ssh/,文件以 id_rsa 的名称保存。对于此示例可以将密码保留为空。密码短语存储在本地,用于加密静态私钥。可能认为它违背了没有密码的目的,但它是增加了一层安全性。它只验证您的密钥,而不验证服务器,而密码则可以。因此,即使您的公钥泄露,也无法使用它,因为只有您自己知道密码。查看 ~/.ssh 目录可以找到带有 .pub 扩展名 (id_rsa.pub) 的公钥和没有扩展名的私钥 (id_rsa)。

要使用私钥访问服务器,需要首先使用 ssh-copy-id 将公钥放在服务器上。

$   ssh-copy-id [-p] -i ~/.ssh/id_rsa.pub [email protected] 接收一个输入公钥文件(使用 -i 标志)并将其存储在远程服务器的 /.ssh 文件夹中的 authorized_keys 文件中。在底部还可以看到添加的键数。要登录,只需使用 ssh <server IP>。系统不会提示进行任何身份验证,且您已正确登录。

现在,从客户端和服务器中删除旧密钥,创建一个带有密码的新密钥。另外,请记住将公钥复制到远程服务器。

尝试使用新密钥连接到服务器。这一次,服务器要求输入密码来验证密钥,然后才允许访问服务器。尝试断开连接,然后重新连接到服务器。这一次,它会再次要求输入密码,即使之前已经输入过密码。 

SSH 代理

SSH 代理管理 SSH 的密钥。使用 SSH 代理,密码缓存在内存中,因此只需要使用一次,且在随后的每一次连接中,都可以直接登录。注意:如果使用 Linux GUI 连接到服务器,则 ssh-agent 已经在运行。如果要连接到堡垒服务器,则需要启动 ssh-agent。使用 ssh-add 添加私钥。$   ssh-add <private-key>ssh-add 是通往 ssh-agent 的网关。它的工作原理如下图所示:

当使用 ssh-add 添加加密的私钥时,系统会提示您输入密码。此密码仅输入一次,然后 ssh-add 解密将其发送给 ssh-agent。要了解 ssh-agent 的作用,看一下客户端和服务器之间的握手。

1. 客户端尝试使用 ssh 进行连接。

2. 服务器然后生成一个唯一的随机挑战并要求客户端使用私钥签名。

3. 客户端然后将该责任转发给 ssh-agent,后者签署该质询并将其转发给服务器。

4. 如果服务器信任客户端的公钥,那么它才会检查签名的真实性。

5. 如果校验成功并且客户端提供的私钥确实是真实的,则客户端和服务器之间建立连接。

注意:每当使用 ssh 建立连接时,密钥既不会公开也不会通过网络发送。如上所示,ssh-agent 代表私钥对服务器发送的消息/请求进行签名,对该密钥执行一些与密钥相关的操作,并将操作结果传递给服务器。

SSH 代理转发

假设通过 ssh 连接到堡垒主机。现在想登录 Github 并克隆一个 repo。但是要登录 Github,需要本地计算机上的 ssh 密钥。那么,如何从堡垒主机连接到 Github 服务器?如上所示,可以将 Github 存储库克隆到本地计算机上,但不能从堡垒主机克隆。一种解决方案是将私钥从本地计算机复制到堡垒主机并从该主机登录到 Github。这种做法并不安全,而且密钥很容易被连接到此堡垒主机的任何人使用。SSH 代理转发通过跳转服务器(也称为跳转盒或代理)透明地连接到远程服务器来解决此问题。无需从本地计算机复制密钥即可发生这种情况。在上面的例子中,堡垒主机是跳转服务器,Github 是远程服务器。要启用 SSH 代理转发,请在跳转服务器上运行以下命令。$ ssh -A <user@distant-server-ip -or-name>-A 标志打开第二个通道,将请求转发回本地计算机。测试一下与 Github 的连接。由于能够成功连接,现在可以将 Github 存储库克隆到你的跳转服务器上。

注意:对于 macOS 用户,ssh-agent 将密钥存储在 macOS 钥匙串中。根据钥匙串设置,可能需要在重新启动后解锁钥匙并重新输入密码。通过将密码存储在钥匙串中,ssh-agent 将在需要时自动使用它们。

SSH 代理的漏洞

当您使用 SSH 代理转发时,会打开一个套接字用于与远程主机通信,这是一个安全风险。假设您通过跳转服务器连接到远程服务器。如果其他具有 root 访问权限的人连接到跳转服务器,他们可以通过套接字访问您的本地 SSH 代理,且可以在其他机器上假装是你。

风险缓解

要保护 SSH 代理转发,可以使用以下技术:

1. 密码:可以使用 ssh-add-x 锁定 ssh-agent。这会使用密码保护 ssh-agent,因此即使在同一网络上的用户也需要密码才能登录你的 shell。还可以使用 ssh-add-X 解锁 ssh-agent。

2. 生物识别:可以使用“Sekey”的备用 ssh-agent。可以使用指纹登录 ssh-agent,而不是使用密码。在 macOS 上使用 Touch ID 登录。

3. ProxyJump:可以使用替代方法通过使用 ProxyJump 的跳转服务器连接到远程服务器,而不是使用 SSH 代理。

代理跳转

当使用 SSH Agent 时,它会自动打开一个新的套接字,用于跳转服务器和远程服务器之间的通信。 ProxyJump 不会打开新的套接字。相反,它通过跳转服务器将本地 SSH 客户端的标准输入和输出转发到远程服务器。将其视为 SSH 会话中的 SSH。 ssh 永远不会在跳转服务器上运行。相反,一个 sshd 的程序连接到远程服务器并将该会话的控制权交还给本地 SSH。由于跳转服务器永远不会创建套接字,因此无法拦截连接,使其更加安全。

设置 ProxyJump

要设置 ProxyJump,需要在 ~/.ssh 文件夹中创建一个配置文件。如果已经拥有该文件,确保不要覆盖它,而是在文件末尾添加以下说明。Host jump-serverHostName 127.0.0.1User piyushPort 2222 Host distant-serverProxyJump jump-serverHostName github.comUser git

其中,

jump-server 和 remote-server 是主机名的别名。

用户是授权建立连接的用户名(拥有私钥来验证连接的用户)。

Port 是主机的端口号。

ProxyJump 是充当本地客户端和远程服务器之间代理的服务器的名称。

而不是使用$   ssh -p 2222 [email protected]可以简单使用$ ssh jump-server要创建 ProxyJump 连接,请使用:$ ssh -J <jump-server-alias> <distant-server-alias>现在可以使用跳转服务器在本地主机和远程服务器之间建立连接。然后就成功建立连接。

结论

使用 SSH 代理,必须进入跳转服务器,然后手动连接到远程服务器。它也有安全问题。但是通过使用 ProxyJump可以立即在本地计算机上安全地建立连接。