介绍
身份验证因素 是用于证明您有权执行某项操作(例如登录系统)的单条信息。 身份验证通道是身份验证系统向用户传递因素或要求用户回复的方式。 密码和安全令牌是身份验证因素的示例; 电脑和电话就是渠道的例子。
SSH 默认使用密码进行身份验证,大多数 SSH 加固说明建议使用 SSH 密钥。 然而,这仍然只是一个因素。 如果坏人破坏了您的计算机,那么他们也可以使用您的密钥来破坏您的服务器。
在本教程中,我们将设置多因素身份验证来解决这个问题。 多因素身份验证 (MFA) 需要多个因素才能进行身份验证或登录。 这意味着一个坏演员必须妥协多件事,比如你的电脑和手机,才能进入。 不同类型的因素通常总结为:
- 你知道的东西,比如密码或安全问题
- 您 拥有 的东西,例如身份验证器应用程序或安全令牌
- 你 是 的东西,比如你的指纹或声音
一个常见因素是 OATH-TOTP 应用程序,例如 Google Authenticator。 OATH-TOTP(Open Authentication Time-Based One-Time Password)是一种开放式协议,可生成一次性使用密码,通常是每 30 秒循环一次的 6 位数字。
本文将介绍如何使用 OATH-TOTP 应用程序和 SSH 密钥启用 SSH 身份验证。 然后,通过 SSH 登录您的服务器将需要两个通道上的两个因素,从而使其比单独使用密码或 SSH 密钥更安全。 此外,我们还将介绍 MFA 的一些其他用例以及一些有用的提示和技巧。
先决条件
要遵循本教程,您将需要:
- 一台 Ubuntu 16.04 服务器,启用了 sudo 非 root 用户、SSH 密钥和防火墙,您可以按照 this Initial Server Setup tutorial 进行设置。
- 安装了 OATH-TOTP 应用程序的智能手机或平板电脑,例如 Google Authenticator(iOS、Android)。
第 1 步 — 安装 Google 的 PAM
在这一步中,我们将安装和配置 Google 的 PAM。
PAM 代表 Pluggable Authentication Module,是 Linux 系统上用于对用户进行身份验证的身份验证基础架构。 因为 Google 制作了 OATH-TOTP 应用程序,所以他们还制作了一个 PAM,它可以生成 TOTP,并且与任何 OATH-TOTP 应用程序完全兼容,例如 Google Authenticator 或 Authy。
首先,更新 Ubuntu 的存储库缓存。
sudo apt-get update
接下来,安装 PAM。
sudo apt-get install libpam-google-authenticator
安装 PAM 后,我们将使用 PAM 附带的帮助应用程序为要添加第二个因素的用户生成 TOTP 密钥。 此密钥是在逐个用户的基础上生成的,而不是在系统范围内生成的。 这意味着每个想要使用 TOTP auth 应用程序的用户都需要登录并运行帮助应用程序以获取他们自己的密钥; 您不能只运行一次即可为所有人启用它(但本教程末尾有一些提示可以为许多用户设置或要求 MFA)。
运行初始化应用程序。
google-authenticator
运行命令后,系统会询问您几个问题。 第一个询问身份验证令牌是否应该基于时间。
OutputDo you want authentication tokens to be time-based (y/n) y
此 PAM 允许基于时间或基于顺序的令牌。 使用 sequential-based tokens 意味着代码从某个点开始,然后在每次使用后递增代码。 使用 基于时间的令牌 意味着代码在经过一定时间后随机更改。 我们将坚持基于时间,因为这是 Google Authenticator 等应用程序所期望的,所以回答 y
是的。
回答完这个问题后,很多输出会滚动过去,包括一个大二维码。 此时,使用手机上的身份验证器应用程序扫描二维码或手动输入密钥。 如果二维码太大而无法扫描,您可以使用二维码上方的 URL 获取较小的版本。 添加后,您会在应用中看到每 30 秒更改一次的六位数代码。
注意:确保将密钥、验证码和恢复码记录在安全的地方,例如密码管理器。 例如,如果您无法访问 TOTP 应用程序,恢复代码是重新获得访问权限的唯一方法。
剩下的问题告诉 PAM 如何运作。 我们将一一进行。
OutputDo you want me to update your "~/.google_authenticator" file (y/n) y
这会将密钥和选项写入 .google_authenticator
文件。 如果你说不,程序退出并且没有写入任何内容,这意味着验证器将无法工作。
OutputDo you want to disallow multiple uses of the same authentication token? This restricts you to one login about every 30s, but it increases your chances to notice or even prevent man-in-the-middle attacks (y/n) y
通过在此处回答“是”,您可以通过使每个代码在使用后立即过期来防止重放攻击。 这可以防止攻击者捕获您刚刚使用的代码并使用它登录。
OutputBy default, tokens are good for 30 seconds and in order to compensate for possible time-skew between the client and the server, we allow an extra token before and after the current time. If you experience problems with poor time synchronization, you can increase the window from its default size of 1:30min to about 4min. Do you want to do so (y/n) n
在这里回答是允许在移动的四分钟窗口中最多 8 个有效代码。 通过回答否,您将其限制为 1:30 分钟滚动窗口中的 3 个有效代码。 除非您发现 1:30 分钟窗口存在问题,否则回答“否”是更安全的选择。
OutputIf the computer that you are logging into isn't hardened against brute-force login attempts, you can enable rate-limiting for the authentication module. By default, this limits attackers to no more than 3 login attempts every 30s. Do you want to enable rate-limiting (y/n) y
速率限制意味着远程攻击者在被阻止之前只能尝试一定数量的猜测。 如果您之前没有直接在 SSH 中配置速率限制,那么现在这样做是一种很好的强化技术。
注意:完成此设置后,如果要备份密钥,可以将~/.google-authenticator
文件复制到受信任的位置。 从那里,您可以在其他系统上部署它或在备份后重新部署它。
现在已经安装并配置了 Google 的 PAM,下一步是配置 SSH 以使用您的 TOTP 密钥。 我们需要将 PAM 告诉 SSH,然后配置 SSH 以使用它。
第 2 步 — 配置 OpenSSH
因为我们将通过 SSH 进行 SSH 更改,所以永远不要关闭您的初始 SSH 连接,这一点很重要。 相反,打开第二个 SSH 会话进行测试。 这是为了避免在 SSH 配置中出现错误时将自己锁定在服务器之外。 一旦一切正常,您就可以安全地关闭任何会话。
开始使用 nano
或您喜欢的文本编辑器打开 sshd
配置文件进行编辑。
sudo nano /etc/pam.d/sshd
将以下行添加到文件的底部。
/etc/pam.d/sshd
. . . # Standard Un*x password updating. @include common-password auth required pam_google_authenticator.so nullok
最后一行末尾的 nullok
字告诉 PAM 此身份验证方法是可选的。 这允许没有 OATH-TOTP 令牌的用户仍然使用他们的 SSH 密钥登录。 一旦所有用户都拥有 OATH-TOTP 令牌,您可以从此行中删除 nullok
以强制执行 MFA。
保存并关闭文件。
接下来,我们将配置 SSH 以支持这种身份验证。 打开 SSH 配置文件进行编辑。
sudo nano /etc/ssh/sshd_config
查找 ChallengeResponseAuthentication
并将其值设置为 yes
。
/etc/ssh/sshd_config
. . . # Change to yes to enable challenge-response passwords (beware issues with # some PAM modules and threads) ChallengeResponseAuthentication yes . . .
保存并关闭文件,然后重新启动 SSH 以重新加载配置文件。 重新启动 sshd
服务不会关闭打开的连接,因此您不会冒险使用此命令锁定自己。
sudo systemctl restart sshd.service
要测试到目前为止一切正常,请打开另一个终端并尝试通过 SSH 登录。 如果您之前创建了 SSH 密钥并正在使用它,您会注意到您不必输入用户密码或 MFA 验证码。 这是因为默认情况下 SSH 密钥会覆盖所有其他身份验证选项。 否则,您应该得到密码和验证码提示。
接下来,要将 SSH 密钥作为一个因素,将验证码作为第二个因素,我们需要告诉 SSH 使用哪些因素,并防止 SSH 密钥覆盖所有其他类型。
第 3 步 — 让 SSH 了解 MFA
重新打开 sshd
配置文件。
sudo nano /etc/ssh/sshd_config
在文件底部添加以下行。 这告诉 SSH 需要哪些身份验证方法。 这一行告诉 SSH 我们需要一个 SSH 密钥和一个密码或一个验证码(或全部三个)。
/etc/ssh/sshd_config
. . . UsePAM yes AuthenticationMethods publickey,password publickey,keyboard-interactive
保存并关闭文件。
接下来,再次打开 PAM sshd
配置文件。
sudo nano /etc/pam.d/sshd
找到行 @include common-auth
并通过添加一个 #
字符作为该行的第一个字符将其注释掉。 这告诉 PAM 不要提示输入密码。
/etc/pam.d/sshd
. . . # Standard Un*x authentication. #@include common-auth . . .
保存并关闭文件,然后重新启动 SSH。
sudo systemctl restart sshd.service
现在尝试使用不同的会话再次登录服务器。 与上次不同,SSH 应该要求您提供验证码。 输入后,您将登录。 即使您没有看到任何表明您的 SSH 密钥已被使用的迹象,但您的登录尝试使用了两个因素。 如果要验证,可以在 SSH 命令后添加 -v
(表示详细):
Example SSH output\. . . debug1: Authentications that can continue: publickey debug1: Next authentication method: publickey debug1: Offering RSA public key: /Users/sammy/.ssh/id_rsa debug1: Server accepts key: pkalg rsa-sha2-512 blen 279 Authenticated with partial success. debug1: Authentications that can continue: password,keyboard-interactive debug1: Next authentication method: keyboard-interactive Verification code:
在输出的最后,您将看到 SSH 在哪里使用您的 SSH 密钥,然后询问验证码。 您现在可以使用 SSH 密钥和一次性密码通过 SSH 登录。 如果要强制执行所有三种身份验证类型,可以执行下一步。
第 4 步 — 添加第三个因素(可选)
在第 3 步中,我们在 sshd_config
文件中列出了批准的身份验证类型:
publickey
(SSH 密钥)password publickey
(密码)keyboard-interactive
(验证码)
尽管我们列出了三个不同的因素,但到目前为止我们选择的选项只允许 SSH 密钥和验证码。 如果您想拥有所有三个因素(SSH 密钥、密码和验证码),只需一次快速更改即可启用所有三个因素。
打开 PAM sshd
配置文件。
sudo nano /etc/pam.d/sshd
找到您之前注释掉的行 #@include common-auth
,并通过删除 #
字符取消注释该行。 保存并关闭文件。 现在再次重新启动 SSH。
sudo systemctl restart sshd.service
通过启用选项 @include common-auth
,PAM 现在会提示输入密码,此外还会检查 SSH 密钥并要求输入验证码,这是我们之前使用的。 现在我们可以在两个不同的渠道上使用我们知道的东西(密码)和我们拥有的两种不同类型的东西(SSH 密钥和验证码)。
到目前为止,本文已经概述了如何使用 SSH 密钥和基于时间的一次性密码启用 MFA。 如果这就是你所需要的,你可以在这里结束。 但是,这并不是进行多因素身份验证的唯一方法。 以下是使用此 PAM 模块进行多因素身份验证的几种其他方法,以及一些有关恢复、自动使用等的提示和技巧。
提示 1 — 恢复访问
与您加固和保护的任何系统一样,您将负责管理该安全性。 在这种情况下,这意味着不会丢失您的 SSH 密钥或 TOTP 密钥,并确保您可以访问您的 TOTP 应用程序。 但是,有时会发生一些事情,您可能会失去对需要进入的按键或应用程序的控制。
丢失 SSH 密钥或 TOTP 密钥
如果您丢失了 SSH 密钥或 TOTP 密钥,恢复可以分为几个步骤。 第一个是在不知道验证码的情况下重新登录,第二个是找到密钥或重新生成它以进行正常的 MFA 登录。
要在丢失在 DigitalOcean Droplet 上生成验证码的密钥后进入,您只需 使用仪表板中的虚拟控制台 使用您的用户名和密码登录。
否则,您将需要具有 sudo 访问权限的管理用户; 确保不要为此用户启用 MFA,而是使用 SSH 密钥。 如果您或其他用户丢失了他们的密钥并且无法登录,那么管理用户可以登录并帮助使用 sudo
为任何用户恢复或重新生成密钥。
登录后,有两种方法可以帮助获取 TOTP 密码:
- 恢复现有密钥
- 生成新密钥
在每个用户的主目录中,密钥和 Google Authenticator 设置保存在 ~/.google-authenticator
中。 该文件的第一行是密钥。 快速获取密钥的方法是执行以下命令,显示google-authenticator
文件的第一行(即 密钥)。 然后,获取该密钥并手动将其输入 TOTP 应用程序。
head -n 1 /home/sammy/.google_authenticator
如果有不使用现有密钥的原因(例如,无法轻松安全地与受影响的用户共享密钥),您可以直接删除 ~/.google-authenticator
文件。 假设您没有强制执行 MFA,这将允许用户仅使用一个因素再次登录。 然后他们可以运行 google-authenticator
来生成新密钥。
无法访问 TOTP 应用程序
如果您需要登录服务器但无权访问 TOTP 应用程序以获取验证码,您仍然可以使用首次创建密钥时显示的恢复码登录。 请注意,这些恢复代码是一次性使用的。 一旦用于登录,则不能再次用作验证码。
提示 2 — 更改身份验证设置
如果您想在初始配置后更改 MFA 设置,而不是使用更新的设置生成新配置,您只需编辑 ~/.google-authenticator
文件即可。 该文件按以下方式布局:
.google-authenticator 布局
<secret key> <options> <recovery codes>
在这个文件中设置的选项在选项部分有一行; 如果您在初始设置期间对特定选项回答“否”,则相应的行将从文件中排除。
以下是您可以对此文件进行的更改:
- 要启用顺序代码而不是基于时间的代码,请将行
" TOTP_AUTH
更改为" HOTP_COUNTER 1
。 - 要允许多次使用单个代码,请删除
" DISALLOW_REUSE
行。 - 要将代码过期窗口延长至 4 分钟,请添加行
" WINDOW_SIZE 17
。 - 要禁用多次失败登录(速率限制),请删除
" RATE_LIMIT 3 30
行。 - 要更改速率限制的阈值,请找到
" RATE_LIMIT 3 30
行并调整数字。 原文中的3
表示一段时间内的尝试次数,30
表示时间段,单位为秒。 - 要禁用恢复代码,请删除文件底部的五个 8 位代码。
提示 3 — 避免对某些帐户进行 MFA
可能存在单个用户或几个服务帐户(即 应用程序使用的帐户,而不是人类)需要在未启用 MFA 的情况下进行 SSH 访问。 例如,某些使用 SSH 的应用程序(如某些 FTP 客户端)可能不支持 MFA。 如果应用程序无法请求验证码,则请求可能会卡住,直到 SSH 连接超时。
只要 /etc/pam.d/sshd
中的几个选项设置正确,您就可以根据每个用户控制使用哪些因素。
要对某些帐户允许 MFA,而对其他帐户只允许 SSH,请确保 /etc/pam.d/sshd
中的以下设置处于活动状态。
/etc/pam.d/sshd
# PAM configuration for the Secure Shell service # Standard Un*x authentication. #@include common-auth . . . # Standard Un*x password updating. @include common-password auth required pam_google_authenticator.so nullok
此处,@include common-auth
被注释掉,因为需要禁用密码。 如果某些帐户要禁用 MFA,则无法强制执行 MFA,因此请在最后一行保留 nullok
选项。
设置此配置后,只需像任何需要 MFA 的用户一样运行 google-authenticator
,不要为只使用 SSH 密钥的用户运行它。
技巧 4 — 使用配置管理自动化设置
许多系统管理员使用 配置管理工具 ,如 Puppet、Chef 或 Ansible 来管理他们的系统。 如果您想使用这样的系统在创建新用户帐户时设置密钥,有一种方法可以做到这一点。
google-authenticator
支持命令行开关以在单个非交互式命令中设置所有选项。 要查看所有选项,您可以键入 google-authenticator --help
。 以下是按照步骤 1 中所述设置所有内容的命令:
google-authenticator -t -d -f -r 3 -R 30 -W
这会回答我们手动回答的所有问题,将其保存到文件中,然后输出密钥、二维码和恢复码。 (如果您添加标志 -q
,则不会有任何输出。)如果您确实以自动方式使用此命令,请确保捕获密钥和/或恢复代码并制作它们可供用户使用。
技巧 5 — 为所有用户强制执行 MFA
如果您希望即使在第一次登录时也对所有用户强制执行 MFA,或者如果您不想依赖用户生成自己的密钥,那么有一种简单的方法来处理这个问题。 您可以简单地为每个用户使用相同的 .google-authenticator
文件,因为文件中没有存储用户特定的数据。
为此,在最初创建配置文件后,特权用户需要将该文件复制到每个主目录的根目录,并将其权限更改为适当的用户。 您还可以将文件复制到 /etc/skel
/ 以便在创建时自动复制到新用户的主目录。
警告:这可能是一个安全风险,因为每个人都共享相同的第二个因素。 这意味着,如果它被泄露,就好像每个用户只有一个因素。 如果您想使用这种方法,请考虑到这一点。
另一种强制创建用户密钥的方法是使用 bash 脚本:
- 创建一个 TOTP 代币,
- 提示他们下载 Google Authenticator 应用程序并扫描将显示的 QR 码,以及
- 检查
.google-authenticator
文件是否已存在后,为他们运行google-authenticator
应用程序。
为确保脚本在用户登录时运行,您可以将其命名为 .bash_login
并将其放置在其主目录的根目录中。
结论
也就是说,通过在两个渠道(您的计算机 + 您的手机)上拥有两个因素(SSH 密钥 + MFA 令牌),您使外部代理很难通过 SSH 强行进入您的机器并大大增加您机器的安全性。