ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Linux服务器SSH登录部署Google Authenticator二次验证实战指南

Linux服务器SSH登录部署Google Authenticator二次验证实战指南 1. 项目概述为什么SSH需要“第二把锁”在运维和开发工作中SSHSecure Shell是我们连接和管理远程Linux服务器的生命线。它默认使用密码或密钥对进行身份验证这看似安全实则暗藏风险。弱密码容易被暴力破解而即便是复杂的密钥一旦私钥文件泄露攻击者也能长驱直入。我见过太多因为单一验证机制被攻破导致服务器沦为“肉鸡”的案例。因此为SSH登录增加一道动态的、基于时间的屏障就成了守护服务器入口的刚需。这就是二次身份验证2FA的价值所在。它遵循“你知道的”密码/密钥和“你拥有的”动态令牌双重验证原则。即使你的密码不幸泄露攻击者没有你手机上实时生成的6位数字码依然无法登录。Google Authenticator谷歌身份验证器是实现这一机制的经典工具它基于TOTP基于时间的一次性密码算法完全离线运行不依赖短信安全又可靠。本文将手把手带你在Linux服务器上为SSH登录部署基于Google Authenticator的二次验证环境。整个过程会深入PAM可插拔认证模块机制不仅告诉你每一步怎么做更会解释背后的原理和每个参数的意义。无论你是个人服务器管理员还是为企业基础设施寻求加固方案这套流程都经得起实战考验。2. 核心原理与架构拆解PAM与TOTP如何协同工作在动手之前我们必须搞清楚整个验证流程的骨架。这能让你在遇到问题时知道该从哪里排查而不是盲目地复制命令。2.1 PAMLinux认证的“总调度中心”PAMPluggable Authentication Modules是Linux系统中处理身份认证的一套灵活框架。你可以把它想象成一个配备了各种认证插件模块的认证总线。当sshdSSH服务进程需要验证用户时它并不自己处理密码或令牌而是把认证请求“抛给”PAM框架。PAM则根据配置文件/etc/pam.d/sshd中定义的“栈”stack按顺序调用一个个认证模块。每个模块只负责一件小事比如pam_unix.so检查系统密码pam_google_authenticator.so则检查Google Authenticator令牌。PAM根据模块的返回结果success, ignore, bad, die等和配置的控制标志required,sufficient等最终决定认证是成功还是失败。这种设计使得增加一种新的认证方式如Google Authenticator变得异常简单只需在PAM配置里插入一行对应的模块调用即可。2.2 TOTP动态密码的“时间之锁”Google Authenticator使用的TOTP算法是核心中的核心。它的原理非常巧妙共享密钥在初始化时服务器和你的手机AppGoogle Authenticator会共享一个相同的密钥一个Base32编码的字符串。这个密钥是后续一切计算的基础必须安全保存。时间因子算法获取当前时间并将其除以一个时间窗口默认30秒得到一个不断递增的时间计数器。HMAC计算使用共享密钥和时间计数器作为输入通过HMAC-SHA1哈希函数计算出一个哈希值。动态截取从上述哈希值中动态截取出6位数字有时是8位这就是你手机上每30秒变化一次的6位数验证码。整个过程是离线和确定性的。服务器和你的手机不需要通信只要它们的时钟大致同步通常允许±1到2个时间窗口的误差就能独立计算出相同的验证码。攻击者即使截获了某一个验证码因为这个码仅在30秒内有效且用过即废他也无法推算出下一个码或共享密钥。2.3 整体认证流程当启用二次验证后一次SSH密码登录的流程变为用户发起SSH连接输入用户名。sshd将认证请求交由PAM处理。PAM首先调用pam_google_authenticator.so模块该模块会提示用户输入Google Authenticator生成的动态验证码。用户输入验证码模块根据该用户家目录下的配置文件~/.google_authenticator中的密钥进行校验。如果验证码正确该模块返回成功。PAM继续执行栈中的下一个模块通常是pam_unix.so要求输入系统密码。用户输入系统密码pam_unix.so模块进行校验。当所有被标记为required的模块都返回成功PAM向sshd返回认证成功登录完成。对于SSH密钥登录流程稍有不同通常配置为仅在密钥认证之后再要求输入验证码这避免了每次交互都输密码的麻烦。3. 环境准备与依赖安装我们以一个典型的CentOS 8/Rocky Linux 8或Ubuntu 20.04/22.04 LTS系统为例。不同发行版的包管理工具和软件包名称略有差异。3.1 系统更新与基础检查首先确保系统是最新的并且已经安装了必要的编译工具和sshd。# CentOS/Rocky/AlmaLinux sudo dnf update -y sudo dnf install -y gcc make pam-devel git # Ubuntu/Debian sudo apt update sudo apt upgrade -y sudo apt install -y build-essential libpam0g-dev git检查SSH服务状态和版本确保它是正常运行的。我们将要修改其PAM配置。sudo systemctl status sshd sshd -V3.2 编译与安装Google Authenticator PAM模块大多数发行版的仓库里都有google-authenticator这个软件包但它通常只包含命令行工具不包含PAM模块。PAM模块需要我们手动编译。这是最关键的一步。# 1. 克隆官方源码如果网络不佳可寻找国内镜像源 git clone https://github.com/google/google-authenticator-libpam.git cd google-authenticator-libpam # 2. 运行自动配置脚本检查编译环境 ./bootstrap.sh # 3. 配置编译选项。--prefix/usr 确保模块安装到标准路径。 ./configure # 4. 编译源码 make # 5. 以root权限安装编译好的文件 sudo make install安装完成后关键的PAM模块文件pam_google_authenticator.so会被安装到/lib64/security/64位系统或/lib/security/目录下。你可以用以下命令验证sudo find / -name pam_google_authenticator.so 2/dev/null同时命令行工具google-authenticator也会被安装到/usr/local/bin/或/usr/bin/。注意如果./bootstrap.sh或./configure报错提示缺少automake、libtool等请根据错误信息安装相应的开发包。例如在Ubuntu上可能需要sudo apt install automake libtool。4. 配置用户与SSH服务在开启全局强制验证之前强烈建议先为一个测试用户配置并在另一个终端保持一个已有的SSH连接不断开以防配置错误把自己锁在服务器外面。4.1 为单个用户初始化Google Authenticator切换到需要启用二次验证的用户这里以testuser为例。sudo su - testuser运行初始化命令google-authenticator这是一个交互式命令行向导会问你几个问题。我的选择和解释如下Do you want authentication tokens to be time-based (y/n) y选择y使用基于时间的TOTP模式。这是标准模式。随后会显示一个巨大的QR Code二维码以及你的密钥、备用紧急刮刮码。立即用手机Google Authenticator App扫描这个二维码这是绑定服务器的唯一机会。同时务必把屏幕上的“备用刮刮码”安全地保存下来比如记在密码管理器或离线文档里。这些码在手机丢失时可用于紧急登录每个只能用一次。Do you want me to update your /home/testuser/.google_authenticator file? (y/n) y选择y将配置保存到用户家目录下的隐藏文件中。Do 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选择y。禁止重复使用同一个令牌。这能有效防止重放攻击。By default, tokens are good for 30 seconds. 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 3 permitted codes (one previous code, the current code, the next code) to 17 permitted codes (for example). Do you want to do so? (y/n) n选择n。除非你服务器和手机时间严重不同步导致验证总失败否则保持默认的3个码窗口前后各容忍一个30秒周期即可。扩大窗口会略微降低安全性。If the computer that you are logging into isnt 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强烈建议选择y。启用速率限制每30秒最多尝试3次。这是防止暴力破解动态码的重要屏障。初始化完成后你的家目录下会生成一个.google_authenticator文件。这个文件极其重要它包含了密钥、设置和备用码。它的权限必须是600仅所有者可读可写否则PAM模块会拒绝工作。ls -la ~/.google_authenticator chmod 600 ~/.google_authenticator4.2 配置PAM以启用二次验证现在我们来修改PAM配置让SSH服务在认证时调用Google Authenticator模块。编辑/etc/pam.d/sshd文件sudo vim /etc/pam.d/sshd我们需要在适当的位置添加一行。位置非常关键它决定了验证码和密码的输入顺序。场景一先验证码后密码最常用安全性高在配置文件中找到用于auth认证的段落。通常会有一行类似于auth substack password-auth。在这行之前插入以下内容# 标准配置先要求Google Authenticator验证码再要求系统密码 auth required pam_google_authenticator.so nullok参数解释auth: 表示这是一个认证类模块。required: 控制标志。表示此模块必须成功但如果它失败PAM会继续运行栈中后续的required模块最后才返回整体失败。这确保了用户无论验证码对错都会看到密码提示避免了给攻击者提示“此用户是否启用了2FA”。pam_google_authenticator.so: 我们刚安装的模块。nullok:至关重要的参数。意思是“如果用户没有配置.google_authenticator文件则跳过此模块视为成功”。这允许你逐用户启用2FA而不是一刀切。在全员推广前务必加上它。场景二仅对密码登录启用2FA密钥登录后启用更友好如果你主要使用SSH密钥登录可能希望只在用密码登录时才要求验证码。或者在密钥认证通过后再要求验证码作为第二因素。这需要结合PAM的auth和session管理并修改SSH服务端配置。一种常见做法是在/etc/ssh/sshd_config中设置AuthenticationMethods publickey,password或keyboard-interactive并在PAM中配置验证码。但这属于更高级的配置初期建议使用场景一。4.3 配置SSH服务端以支持交互式验证默认情况下SSH的密码认证是直接传递密码给PAM的。但Google Authenticator的提示是交互式的需要SSH以“键盘交互”模式工作。修改/etc/ssh/sshd_configsudo vim /etc/ssh/sshd_config确保或修改以下行# 启用挑战-响应键盘交互认证这是PAM显示提示所必需的 ChallengeResponseAuthentication yes # 也可以使用这个更新的参数效果类似 KbdInteractiveAuthentication yes # 确保密码认证是开启的因为我们仍需要密码作为第一或第二因素 PasswordAuthentication yes # 如果你想同时允许密钥认证确保公钥认证开启 PubkeyAuthentication yes重要提示PasswordAuthentication和ChallengeResponseAuthentication是两个独立的开关。即使你设置了PasswordAuthentication no只要ChallengeResponseAuthentication yesPAM的交互流程包括我们的验证码依然可以工作。但为了清晰的“密码验证码”流程建议两者都开启。保存并关闭文件后务必重启SSH服务以使配置生效。# CentOS/Rocky 7/8 sudo systemctl restart sshd # Ubuntu/Debian sudo systemctl restart ssh重启前务必确保你当前有一个活跃的SSH会话没有退出这是你的“救命通道”。在新窗口尝试连接测试确认无误后再关闭旧会话。5. 完整登录流程测试与验证现在从另一台机器或一个新的终端窗口尝试用密码方式SSH登录你的测试用户。ssh testuseryour_server_ip你应该会看到与以往不同的提示序列Password: Verification code:或者直接就是Verification code: Password:这取决于你在PAM配置中插入模块的位置。输入你手机Google Authenticator App上当前显示的6位数字码回车然后输入你的系统密码。如果一切配置正确你将成功登录。测试要点验证码时效性等待30秒让手机上的验证码刷新后尝试使用过期的码登录应该失败。错误码测试故意输入错误的验证码应该被拒绝。速率限制测试快速连续输入错误验证码3次看看第4次是否被延迟或拒绝。备用码测试使用你保存的16位备用刮刮码之一进行登录通常在输入验证码的地方直接输入备用码。成功后检查~/.google_authenticator文件会发现该备用码已被标记为使用过。6. 生产环境部署的进阶配置与避坑指南为单个用户配置成功只是第一步。在生产环境中为整个团队或所有用户部署需要考虑更多。6.1 批量初始化与密钥分发手动为每个用户运行google-authenticator命令是不现实的。你可以编写一个脚本自动化这个过程#!/bin/bash USERNAME$1 sudo -u $USERNAME google-authenticator -t -d -f -r 3 -R 30 -w 3 -Q UTF8 EOF y y y n y EOF # 设置正确的文件权限 sudo chmod 600 /home/$USERNAME/.google_authenticator sudo chown $USERNAME:$USERNAME /home/$USERNAME/.google_authenticator脚本参数解释-t: 使用TOTP时间模式。-d: 禁止令牌复用。-f: 强制写入文件不交互确认。-r 3 -R 30: 速率限制每30秒3次尝试。-w 3: 时间容差窗口为3默认值。-Q UTF8: 二维码的字符集。 EOF ... EOF: 这是Here Document用于非交互式地回答所有提示问题全是y和n。但请注意此脚本生成的密钥和二维码会输出到终端你需要设计安全的方式如通过加密通道将密钥或二维码分发给相应用户。更好的做法是结合配置管理工具Ansible, SaltStack和密钥管理系统来操作。6.2 高可用与时钟同步问题TOTP严重依赖时间同步。如果服务器时间漂移超过±30秒默认窗口验证就会失败。确保NTP服务确保所有服务器都运行并正确同步到可靠的NTP源。sudo timedatectl status sudo systemctl enable --now chronyd # CentOS/Rocky sudo systemctl enable --now systemd-timesyncd # Ubuntu调整时间窗口如果因网络等原因无法完美同步可以在初始化用户或PAM模块调用时扩大窗口。例如在PAM配置行末尾添加window_size5允许前后共5个时间片约2.5分钟。但这会略微降低安全性。auth required pam_google_authenticator.so nullok window_size56.3 紧急访问与“后门”方案永远要为自己留一条紧急访问路径防止2FA配置出错或全员被锁。保留一个特权账户不启用2FA例如一个仅用于紧急情况、使用非常复杂密码且限制IP登录的breakglass账户。不要在日常使用它。使用SSH证书认证这是比密钥更强大的方式。你可以颁发一个短期有效的SSH用户证书即使启用了2FA持有有效证书的用户也可以直接登录。这需要配置SSH CA。物理控制台或带外管理对于关键服务器确保你有通过物理控制台、ILO、iDRAC等带外管理方式进行访问的能力。妥善保管备用刮刮码将生成的备用码加密后存储在多个安全的地方。6.4 与现有自动化脚本/工具的兼容性启用2FA后所有依赖SSH密码认证的自动化脚本如rsync、scp、cron作业中的远程命令都会中断。解决方案是改用SSH密钥认证并为这些密钥设置强密码保护。使用sshpass不推荐可以传递密码和验证码但密码会暴露在命令行或环境变量中极不安全。使用Expect脚本可以模拟交互过程但同样存在安全和管理复杂度问题。最佳实践为自动化任务创建专用的、权限最小化的服务账户并使用SSH密钥认证。如果该账户风险极高可考虑为其单独配置一个硬件令牌如YubiKey进行2FA但这需要更复杂的PAM配置如pam_yubico。7. 故障排查与常见问题实录即使按照步骤操作你也可能会遇到一些问题。这里记录了我踩过的坑和解决方案。7.1 常见错误与解决方法问题现象可能原因排查与解决Permission denied后直接断开无验证码提示。1. PAM模块路径错误。2..google_authenticator文件权限不对。3. PAM配置行语法错误或位置不当。1.sudo ls -la /lib*/security/pam_google_authenticator.so确认模块存在。2.sudo ls -la ~/.google_authenticator确认权限为600属主正确。3.sudo cat /etc/pam.d/sshd检查添加的行确保拼写正确nullok参数已加。提示Verification code:但输入正确码后仍被拒绝。1. 服务器与手机时间不同步。2. 初始化时密钥未正确绑定手机扫了码但服务器没保存。3. 速率限制触发。1. 分别在服务器和手机执行date命令检查时间差。配置NTP。2. 重新运行google-authenticator为用户初始化并重新扫码绑定。3. 等待30秒后再试。登录时只提示Password:没有Verification code:。1. SSH配置未启用ChallengeResponseAuthentication。2. PAM配置中模块被放在了password-authsubstack 之后或include之后。1. 确认/etc/ssh/sshd_config中ChallengeResponseAuthentication yes已设置并重启sshd。2. 将auth required pam_google_authenticator.so nullok行移动到auth substack password-auth这行的前面。特定用户登录正常但另一用户登录时直接跳过验证码。该用户家目录下没有.google_authenticator文件。这是nullok参数在起作用。为该用户运行google-authenticator命令进行初始化。编译安装时出错提示fatal error: security/pam_modules.h: No such file or directory。缺少PAM开发头文件。CentOS/Rocky:sudo dnf install pam-develUbuntu/Debian:sudo apt install libpam0g-dev7.2 调试技巧当问题复杂时可以启用更详细的日志。查看PAM调试日志编辑/etc/pam.d/sshd在你添加的那一行末尾加上debug参数。auth required pam_google_authenticator.so nullok debug然后通过sudo tail -f /var/log/secureCentOS/Rocky或sudo tail -f /var/log/auth.logUbuntu/Debian查看SSH登录尝试的详细PAM流程。查看SSH服务端详细日志在sshd_config中增加LogLevel DEBUG3重启sshd。然后通过journalctl -u sshd -f或查看/var/log/secure获取极详细的连接和认证过程日志。注意调试完毕后请调低日志级别因为DEBUG3会产生大量日志。7.3 我个人的实操心得永远保持一个活动会话在修改/etc/pam.d/sshd和/etc/ssh/sshd_config并重启服务前务必在另一个终端保持一个已登录的root或sudo会话。这是你的“安全绳”。从测试用户开始不要直接为root或常用账号配置。先创建一个test_2fa用户完整测试流程。备份配置文件在修改前对/etc/pam.d/sshd和/etc/ssh/sshd_config进行备份。sudo cp /etc/pam.d/sshd /etc/pam.d/sshd.bak。理解nullok的双刃剑nullok方便了逐用户部署但也意味着攻击者可以通过观察是否出现验证码提示来判断哪些用户配置了2FA。在全员部署完成后可以考虑移除nullok这样未配置的用户将无法登录安全性更高。手机App不只是Google Authenticator除了官方的Google AuthenticatorAuthy、Microsoft Authenticator、1Password、Bitwarden等密码管理器都支持扫描TOTP二维码。我更喜欢用Authy因为它支持多设备同步和加密备份换手机时不会丢失所有令牌。密钥备份至关重要那个.google_authenticator文件里的密钥是恢复2FA配置的唯一凭证。在初始化用户后应该安全地备份这个密钥加密后存储。这样即使服务器硬盘损坏你也可以为用户重新生成相同的二维码。部署SSH二次验证尤其是基于Google Authenticator的方案是一次提升服务器安全基线的重要实践。它并不复杂但需要对PAM和SSH配置有清晰的理解。通过本文的步骤和原理讲解你应该能够稳健地完成部署。记住安全是一个过程而不是一个状态。启用2FA后结合强密码、定期更新、最小权限原则和全面的日志监控才能构建起纵深防御体系。
返回列表