本教程的先前版本由 Jamie Scaife 编写。
介绍
Linux 服务器通常通过连接到 OpenSSH 服务器使用 SSH 进行远程管理,这是 Ubuntu、Debian、CentOS、FreeBSD 和大多数其他基于 Linux/BSD 的系统中使用的默认 SSH 服务器软件。 为保护 SSH 的服务器端方面付出了巨大的努力,因为 SSH 充当您服务器的入口。
但是,考虑客户端的安全性也很重要,例如 OpenSSH 客户端。
OpenSSH 客户端是 SSH 的“客户端”,也称为 ssh
命令。 您可以在 SSH Essentials: Working with SSH Servers, Clients, and Keys 中了解有关 SSH 客户端-服务器模型的更多信息。
在服务器端强化 SSH 时,主要目标是让恶意行为者更难访问您的服务器。 但是,客户端的强化是非常不同的,因为您正在努力保护和保护您的 SSH 连接和客户端免受各种不同的威胁,包括:
- 网络上的攻击者,称为“中间人”攻击。
- 受损或恶意服务器发送格式错误的数据包、恶意控制序列或大量数据以使您的客户端过载。
- 人为错误,例如错误输入服务器地址或配置值。
在本教程中,您将强化 Ubuntu 20.04 OpenSSH 客户端,以帮助确保传出 SSH 连接尽可能安全。
先决条件
要完成本教程,您需要:
- 您将用作 SSH 客户端的设备,例如:
- 您的个人电脑
- SSH “跳转主机”或“堡垒主机”
- 按照 Initial Server Setup with Ubuntu 20.04 设置的 Ubuntu 20.04 服务器,包括 sudo 非 root 用户
- 您要连接的 SSH 服务器,例如:
准备好这些之后,以非 root 用户身份登录到您的 SSH 客户端设备即可开始。
第 1 步——一般硬化
在第一步中,您将实施一些初始强化配置,以提高 SSH 客户端的整体安全性。
最适合您的客户端的确切加固配置在很大程度上取决于您自己的 威胁模型和风险阈值 。 但是,此步骤中描述的配置是一个通用的、全方位的安全配置,应该适合大多数用户。
OpenSSH 客户端的许多加固配置是使用全局 OpenSSH 客户端配置文件实现的,该文件位于 /etc/ssh/ssh_config
。 除了这个文件,一些配置也可以使用你的用户的本地 SSH 配置文件来设置,位于 ~/.ssh/config
。
设置本教程中的大多数强化选项。 在继续之前,最好先备份现有配置文件,以便万一出现问题时可以恢复它。
使用以下 cp
命令创建文件的备份:
sudo cp /etc/ssh/ssh_config /etc/ssh/ssh_config.bak cp ~/.ssh/config ~/.ssh/config.bak
这些命令会将文件的备份副本保存在其默认位置,但添加了 .bak
扩展名。
请注意,如果您过去没有使用过本地 SSH 配置文件 (~/.ssh/config
),它可能不存在。 如果是这种情况,现在可以放心地忽略它。
您现在可以使用 nano
或您喜欢的文本编辑器打开全局配置文件,以开始实施初始强化措施:
sudo nano /etc/ssh/ssh_config
注意: OpenSSH 客户端配置文件包括许多默认选项和配置。 根据您现有的客户端设置,可能已经设置了一些推荐的强化选项。
编辑配置文件时,默认情况下,某些选项可能会在行首使用单个哈希字符 (#
) 注释掉。 要编辑这些选项或启用该选项,您需要通过删除哈希来取消注释它们。
首先,如果您不使用 X11 显示转发,请通过设置以下选项禁用它:
/etc/ssh/ssh_config
ForwardX11 no ForwardX11Trusted no
X11 转发允许通过 SSH 连接显示远程图形应用程序,但这在实践中很少使用。 通过禁用它,您可以防止潜在的恶意或受损服务器尝试将 X11 会话转发到您的客户端,这在某些情况下可以允许绕过文件系统权限,或监控本地击键。
接下来,考虑禁用 SSH 隧道。 SSH 隧道使用非常广泛,因此您可能需要保持启用它。 您通常会知道您是否正在使用它。 如果您的特定设置不需要它,您可以安全地禁用它作为进一步的强化措施:
/etc/ssh/ssh_config
Tunnel no
如果不需要,您还应该考虑禁用 SSH 代理转发,以防止服务器请求使用本地 SSH 代理来验证向前的 SSH 连接:
/etc/ssh/ssh_config
ForwardAgent no
在大多数情况下,您的 SSH 客户端将被配置为在连接到服务器时使用密码身份验证或公钥身份验证。 但是,OpenSSH 客户端也支持其他的身份验证方式,其中一些是默认启用的。 如果不需要这些,可以禁用它们以进一步减少客户端的潜在攻击面:
/etc/ssh/ssh_config
GSSAPIAuthentication no HostbasedAuthentication no
如果您想了解更多关于 SSH 中可用的一些其他身份验证方法的信息,您可能希望查看这些资源:
OpenSSH 客户端允许您在连接到服务器时自动传递自定义环境变量,例如,设置语言首选项或配置终端设置。 但是,如果您的设置中不需要这样做,您可以通过确保 SendEnv
选项被注释掉或完全删除来防止发送任何变量:
/etc/ssh/ssh_config
# SendEnv
最后,您应该确保启用了严格的主机密钥检查,以确保在远程服务器的主机密钥/指纹更改或首次连接到新服务器时收到适当的警告:
/etc/ssh/ssh_config
StrictHostKeyChecking ask
这将阻止您在已知主机密钥发生更改时连接到服务器,这可能意味着服务器已重建或升级,或者可能表明正在进行的中间人攻击。
首次连接到新服务器时,您的 SSH 客户端会询问您是否要接受主机密钥并将其保存在您的 ~/.ssh/known_hosts
文件中。 在接受主机密钥之前验证主机密钥很重要,这通常涉及询问服务器管理员或浏览服务的文档(在 GitHub/GitLab 和其他类似服务的情况下)。
保存并退出文件。
现在您已经完成了初始配置文件的强化,您应该通过在测试模式下运行 SSH 来验证新配置的语法:
ssh -G .
您可以将 .
替换为任何主机名,以测试/模拟 Match
或 Host
块中包含的任何设置。
如果您的配置文件具有有效的语法,则将打印出适用于该特定连接的选项。 如果出现语法错误,将输出描述该问题的输出。
您无需重新启动任何系统服务即可使新配置生效,但如果您希望现有 SSH 会话继承新设置,则需要重新建立它们。
在这一步中,您完成了对 OpenSSH 客户端配置文件的一些常规强化。 接下来,您将限制可用于 SSH 连接的密码。
第 2 步 — 限制可用密码
OpenSSH 支持许多不同的 密码算法来通过连接加密数据 。 在此步骤中,您将禁用 SSH 客户端中已弃用或遗留的密码套件。
首先在 nano
或您喜欢的文本编辑器中打开您的全局配置文件:
sudo nano /etc/ssh/ssh_config
确保现有的 Ciphers
配置行通过在其前面加上单个哈希 (#
) 来注释掉。
然后,将以下内容添加到文件顶部:
/etc/ssh/ssh_config
Ciphers -arcfour*,-*cbc
这将禁用旧的 Arcfour 密码,以及所有使用 密码块链接 (CBC) 的密码,不再推荐使用这些密码。
如果需要连接到仅支持这些旧密码的系统,您可以使用 Match
块显式重新启用特定主机所需的密码。 例如,要为特定的旧主机启用 3des-cbc
密码,可以使用以下配置:
/etc/ssh/ssh_config
Match host legacy-server.your-domain Ciphers +3des-cbc
完成编辑后保存并退出文件。 如果您正在使用 nano
按 CTRL+O
然后按 ENTER
保存文件,然后按 CTRL+X
退出。
最后,与第 1 步一样,测试您的 SSH 客户端配置以检查是否存在任何潜在错误:
ssh -G .
如果您添加了 Match
块以启用特定主机的旧密码,您还可以通过指定关联的主机地址在测试期间专门针对该配置:
ssh -G legacy-server.your-domain
您已经保护了 SSH 客户端可用的密码。 接下来,您将查看 SSH 客户端使用的文件的访问权限。
第 3 步 — 保护配置文件和私钥权限
在此步骤中,您将锁定 SSH 客户端配置文件和私钥的权限,以帮助防止意外或恶意更改或私钥泄露。 这在多个用户之间使用共享客户端设备时特别有用。
默认情况下,在全新安装的 Ubuntu 上,OpenSSH 客户端配置文件被配置为每个用户只能编辑自己的本地配置文件 (~/.ssh/config
),并且需要 sudo/administrative 访问权限才能编辑系统范围的配置 (/etc/ssh/ssh_config
)。
但是,在某些情况下,特别是在已经存在很长时间的系统上,这些配置文件的权限可能会被意外修改或调整,因此最好重新设置它们以确保配置安全。
您可以首先使用 stat
命令检查系统范围的 OpenSSH 客户端配置文件的当前权限值,您可以使用该命令显示状态或文件和/或文件系统对象:
stat -c "%a %A %U:%G" /etc/ssh/ssh_config
您使用 -c
参数来指定自定义输出格式。
注意:在某些操作系统上,例如 macOS,您需要使用 -f
选项来指定自定义格式,而不是 -c
。
在这种情况下,%A %a %U:%G
选项将以八进制和人类可读格式打印文件的权限,以及拥有该文件的用户/组。
这将输出类似于以下内容:
Output644 -rw-r--r-- root:root
在这种情况下,权限是正确的,root 完全拥有该文件,并且只有 root 有权写入/修改它。
注意:如果你想在继续之前更新你对 Linux 权限的知识,你可能希望查看 An Introduction to Linux Permissions。
但是,如果您自己的输出不同,则应使用以下命令将权限重置为默认值:
sudo chown root:root /etc/ssh/ssh_config sudo chmod 644 /etc/ssh/ssh_config
如果您在此步骤的前面重复 stat
命令,您现在将收到系统范围配置文件的正确值。
接下来,您可以对自己的本地 SSH 客户端配置文件执行相同的检查,如果您有:
stat -c "%a %A %U:%G" ~/.ssh/config
现在 stat
命令应该输出以下内容:
Output644 -rw--r--r-- user:user
如果您自己的客户端配置文件权限的权限有任何不同,您应该使用以下命令重置它们,类似于前面的步骤:
chown user:user ~/.ssh/config chmod 644 ~/.ssh/config
接下来,您可以检查您在 ~/.ssh
目录中拥有的每个 SSH 私钥的权限,因为这些文件只能由您自己访问,而不能由系统上的任何其他用户访问。
首先打印每个私钥的当前权限和所有权值:
stat -c "%a %A %U:%G" ~/.ssh/id_rsa
这将输出类似于以下内容:
Output600 -rw------- user:user
正确锁定私钥文件的权限非常重要,因为如果不这样做,您设备的其他用户可能会窃取它们并访问相关的服务器或远程用户帐户。
如果权限配置不正确,请在每个私钥文件上使用以下命令将其重置为安全默认值:
chown user:user ~/.ssh/id_rsa chmod 600 ~/.ssh/id_rsa
在此步骤中,您评估并锁定了 SSH 客户端配置文件和私钥的文件权限。 接下来,您将实施出站许可名单以限制您的客户端能够连接到哪些服务器。
第 4 步 — 使用主机白名单限制传出连接
在这最后一步中,您将实施一个传出许可名单,以限制您的 SSH 客户端能够连接到的主机。 这对于共享/多用户系统以及 SSH 跳转主机或堡垒主机特别有用。
此安全控制专门设计用于帮助防止人为错误/错误,例如输入错误的服务器地址或主机名。 用户可以通过编辑他们的本地配置文件轻松绕过它,因此它不是为了防御恶意用户/参与者而设计的。
如果要在网络级别限制出站连接,正确的方法是使用防火墙规则。 这超出了本教程的范围,但您可以查看 UFW Essentials: Common Firewall Rules and Commands。
但是,如果您想添加一些额外的故障保险,那么这种安全控制可能对您有益。
它通过在 SSH 客户端配置文件中使用通配符规则来工作,以 null route 所有出站连接,除了到特定地址或主机名的连接。 这意味着,如果您不小心输入了错误的服务器地址,或者尝试连接到您不应该连接的服务器,请求将立即停止,让您有机会意识到自己的错误并采取纠正措施。
您可以在系统级别 (/etc/ssh/ssh_config
) 或使用本地用户配置文件 (~/.ssh/config
) 应用此功能。 在本例中,我们将使用本地用户配置文件。
首先使用 nano
打开文件,如果它不存在则创建它:
nano ~/.ssh/config
在文件的底部,添加以下内容,替换为您自己的允许 IP 地址和主机名列表:
~/.ssh/config
Match host !203.0.113.1,!192.0.2.1,!server1.your-domain,!github.com,* Hostname localhost
此配置告诉您的 SSH 客户端,对于列表中包含 而非 的任何主机或 IP,客户端应在尝试连接之前替换名称 localhost
。 在 Match
行末尾不带前缀感叹号选项的通配符 (*
) 选项可确保未包含在列表中的任何主机默认为空路由。
您必须在 IP 地址或主机名前加上感叹号 (!
),因为这会告诉 SSH not 对主机名或 IP 地址应用空路由。 此外,您必须使用逗号分隔列表中的每个项目。
如果您也在您的机器上运行 SSH 服务器,您可能希望使用 localhost
以外的主机名值,因为这会导致将空路由连接发送到您自己的本地 SSH 服务器,这可能适得其反或令人困惑。 任何空路由主机名都是可接受的,例如 null
、do-not-use
或 disallowed-server
。
完成更改后保存并关闭文件。
您现在可以通过尝试使用 SSH 客户端连接到不允许的目标来测试配置是否正常工作。 例如:
ssh disallowed.your-domain
如果配置正常工作,您将立即收到类似于以下内容的错误:
OutputCannot connect to localhost: connection refused
但是,当您尝试连接到允许的目的地时,连接将照常成功。
在这最后一步中,您实施了一些额外的故障保护措施,以帮助防止在使用 SSH 客户端时出现人为错误和错误。
结论
在本文中,您查看了 OpenSSH 客户端配置并实施了各种强化措施。
这将提高您的传出 SSH 连接的安全性,并有助于确保您的本地配置文件不会被其他用户意外或恶意修改。
您可能希望查看 OpenSSH 客户端及其相关配置文件的手册页,以确定您想要进行的任何潜在的进一步调整:
最后,如果您也想在服务器端强化 OpenSSH,请查看 如何在 Ubuntu 20.04 上强化 OpenSSH。