ARTICLE DETAIL

资讯详情

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

为Linux服务器SSH登录配置Google Authenticator二次验证

为Linux服务器SSH登录配置Google Authenticator二次验证 1. 项目概述为什么要在SSH上启用二次验证如果你管理过任何一台暴露在公网的Linux服务器大概率经历过这样的场景深夜被安全告警惊醒日志里充斥着来自全球各地IP的SSH暴力破解尝试。用户名root、admin、ubuntu轮番上阵密码字典永不停歇。单靠一个密码就像给家门只装了一把普通的挂锁在自动化攻击工具面前形同虚设。这就是我们今天要解决的问题核心为SSH这把“钥匙”再加一道坚固的“门闩”——基于时间的一次性密码TOTP二次身份验证2FA。我选择Google Authenticator谷歌身份验证器来实现这个目标原因很实际它开源、免费、成熟并且不依赖短信避免了SIM卡劫持风险或特定硬件。其原理是服务器和你的手机App共享一个密钥种子然后基于精确的UTC时间和这个种子通过HMAC-SHA1算法动态生成一个6位数字每30秒刷新一次。即使攻击者窃取了你的SSH密码没有你手机上实时变化的这串数字他也无法登录。整个方案的核心是Linux的PAM可插拔认证模块框架它允许我们在用户输入密码之后再插入一个自定义的认证环节。这个配置过程并不复杂但每一步都关乎安全性和可用性的平衡。接下来我会带你从零开始在CentOS 7/8或Ubuntu 20.04/22.04这类主流发行版上完整部署这套环境。我会重点解释每个配置项背后的安全考量并分享我在生产环境中踩过的坑和总结的技巧确保你配置完后既能高枕无忧又不会把自己锁在门外。2. 核心组件与工作原理深度解析在动手之前我们必须理解几个核心组件是如何协同工作的。这能帮助你在出问题时快速定位而不是对着报错信息盲目尝试。2.1 PAMLinux认证的“调度中心”可以把PAM想象成Linux系统认证流程的“总调度中心”。当任何服务如login、su、ssh需要进行用户认证时它并不直接处理密码而是将认证请求“委托”给PAM。PAM则根据一系列配置文件位于/etc/pam.d/来决定认证的流程。一个PAM配置文件由多行“规则”组成每行定义了一个模块及其控制标志和行为。规则格式通常为模块类型 控制标志 模块路径 [模块参数]对于我们来说最关键的是auth类型负责验证用户身份和pam_google_authenticator.so这个模块。PAM会按顺序执行这些规则而控制标志如required、sufficient决定了单个模块的成功或失败对整体认证结果的影响。理解这一点是避免配置后导致所有用户包括你自己都无法登录的关键。2.2 Google Authenticator PAM模块桥梁与验证器libpam-google-authenticator这个软件包提供了核心的PAM模块pam_google_authenticator.so和一个同名的用户初始化工具google-authenticator。它们分工明确初始化工具 (google-authenticator)由每个用户独立运行。它会做几件事在用户家目录下生成一个隐藏文件.google_authenticator里面包含了加密的密钥种子、备用紧急刮刮码、以及一些配置选项。在终端显示一个二维码和文本密钥供你用Authenticator App扫描或手动输入。交互式地询问你一系列配置问题如是否允许令牌重复使用、时间窗口等。PAM模块 (pam_google_authenticator.so)在SSH登录过程中被PAM调用。它的工作很简单提示用户输入手机上显示的6位验证码然后读取该用户家目录下的.google_authenticator文件用同样的算法TOTP计算当前时间窗口应有的验证码并进行比对。2.3 SSHD与PAM的握手流程当我们为sshd服务启用PAM认证后默认就是开启的一次SSH密码登录的流程就变成了用户通过SSH客户端连接。sshd将用户名和密码提交给PAM处理。PAM执行/etc/pam.d/sshd中定义的auth规则链。首先可能先通过pam_unix.so模块验证系统密码/etc/shadow。密码验证通过后接着执行pam_google_authenticator.so模块。该模块提示用户“Verification code:“。用户输入手机App上当前的6位数字。PAM模块验证该数字。验证通过整个auth流程成功。PAM将成功结果返回给sshdsshd允许登录。关键点二次验证发生在系统密码验证之后。这意味着攻击者必须先猜对你的系统密码才会看到二次验证的提示。这本身就极大地提高了攻击门槛。3. 分步部署与配置实操理论清晰后我们进入实操环节。请务必在一个已有稳定控制台访问权限如VNC、云服务商控制台的测试环境中进行以防配置失误导致SSH访问中断。3.1 系统环境准备与软件安装首先更新系统并安装必要的软件包。不同发行版的包名略有差异。对于RHEL/CentOS/Rocky Linux/AlmaLinuxsudo yum update -y sudo yum install epel-release -y # CentOS 7需要先启用EPEL仓库 sudo yum install google-authenticator qrencode -yqrencode工具用于在终端生成二维码方便手机扫描非必须但推荐安装。对于Ubuntu/Debiansudo apt update sudo apt upgrade -y sudo apt install libpam-google-authenticator qrencode -y安装完成后关键的PAM模块文件pam_google_authenticator.so通常会被放置在/lib64/security/或/lib/security/目录下。3.2 为用户启用Google Authenticator这一步需要以每个需要启用二次验证的用户的身份来执行因为密钥文件会生成在该用户的家目录下。千万不要用root运行后以为所有用户都生效了。假设我们要为当前用户zhangsan启用# 确保你是 zhangsan或者用 su - zhangsan 切换过去 google-authenticator运行命令后会进入一个交互式配置界面生成密钥首先会问“Do you want authentication tokens to be time-based (y/n)“输入y。这是TOTP模式。显示二维码和密钥终端会显示一个巨大的ASCII艺术二维码如果支持和一行“Your secret key is: XXXX…”的文本。同时显示你的“紧急刮刮码”。立即用手机App绑定打开手机上的Google Authenticator、Microsoft Authenticator、Authy等任何支持TOTP的App。选择“添加账户” - “扫描二维码”对准终端上的二维码。如果扫描失败例如通过SSH连接时终端渲染问题可以选择“手动输入”填入上面显示的文本密钥并设置一个账户名如server_zhangsan。绑定成功后App里会开始每30秒刷新一个6位验证码。回答配置问题程序会连续问几个问题我的个人推荐配置如下输入y或nDo you want me to update your /home/zhangsan/.google_authenticator file? (y/n)-y。必须同意才能保存配置。Do you want to disallow multiple uses of the same authentication token? (y/n)-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. Do you want to do so? (y/n)-y。允许前后一个时间窗口共90秒的容错应对手机和服务器之间可能存在的微小时间差。这是避免验证失败的关键设置。If 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。启用速率限制防止暴力破解验证码。配置完成后家目录下会生成.google_authenticator文件。务必妥善备份这个文件它是你账户二次验证的根。你可以将其加密后离线存储。如果丢失且没有备份紧急刮刮码你将永久无法通过该账户登录。重要提示.google_authenticator文件权限默认是600仅所有者可读可写这很重要不要修改它。3.3 配置SSH服务使用PAM模块现在我们需要告诉SSH在认证时使用我们刚刚配置好的Google Authenticator模块。编辑PAM中针对SSH服务的配置文件sudo vim /etc/pam.d/sshd找到与auth相关的行。通常我们需要在系统密码认证之后、会话管理之前添加我们的模块。一个稳妥的位置是在include common-auth这行Ubuntu或auth substack password-auth这行CentOS之后添加。例如在Ubuntu中# 标准密码认证 include common-auth # 添加Google Authenticator作为二次验证 auth required pam_google_authenticator.so nullok关键参数nullok的意思是如果用户没有配置.google_authenticator文件则跳过此模块允许其仅用密码登录。在初始部署阶段强烈建议加上nullok这样你可以逐个为用户启用2FA而不会影响其他未配置的用户。待所有用户都配置完毕并测试无误后可以移除nullok以强制要求所有用户都必须使用2FA。3.4 配置SSH守护进程 (sshd)接下来需要确保SSH服务本身启用了PAM认证并调整交互式认证的行为。编辑SSH主配置文件sudo vim /etc/ssh/sshd_config找到并确认或修改以下参数# 确保PAM认证是开启的默认通常是 yes UsePAM yes # 将密码认证方式改为交互式键盘认证因为我们需要先后输入密码和验证码 PasswordAuthentication yes ChallengeResponseAuthentication yes # 关键启用挑战-应答认证 AuthenticationMethods publickey,password publickey,keyboard-interactive最后一行AuthenticationMethods是控制认证方法顺序和组合的关键指令。它的含义是publickey,password允许先公钥认证如果失败再尝试密码认证。publickey,keyboard-interactive允许先公钥认证如果失败再尝试键盘交互认证PAM会接管这个流程依次询问密码和验证码。更精细和安全的配置可以是AuthenticationMethods publickey keyboard-interactive这表示要求必须同时满足公钥和键盘交互认证即多因子。但对于初次配置我建议先使用publickey,keyboard-interactive这种“或”的关系避免把自己锁在外面。配置完成后保存文件。重要安全提醒在修改任何SSH配置前请确保你有一个活跃的SSH会话窗口不要关闭并且已经配置并测试了SSH密钥对登录。这是你的“逃生通道”。如果新配置导致密码登录失败你还可以用密钥登录进来修复问题。3.5 重启服务与初步测试让所有配置生效sudo systemctl restart sshd不要关闭当前的SSH连接窗口新开一个终端窗口尝试用密码登录ssh zhangsanyour_server_ip你将会经历输入用户密码。密码正确后提示Verification code:。打开手机Authenticator App输入当前显示的6位数字。登录成功。如果成功恭喜你核心功能已就绪。如果失败请保持原有连接查看下一章节的排查指南。4. 高级配置、优化与安全加固基础功能跑通后我们可以进行一些优化和加固让整个体系更安全、更易用。4.1 为不同用户或组设置不同策略你可能不想对所有用户一刀切。例如希望root用户必须使用2FA而一个仅用于内部同步的backup用户则不需要。PAM可以通过条件判断来实现。方法一使用pam_succeed_if模块跳过特定用户在/etc/pam.d/sshd中在pam_google_authenticator行之前添加auth [success1 defaultignore] pam_succeed_if.so user in backup:syncuser auth required pam_google_authenticator.so nullok这行规则的意思是如果登录用户是backup或syncuser则跳过下一行success1即不执行Google Authenticator验证。其他用户则继续执行。方法二为root用户创建独立配置更推荐有时我们希望root的认证更严格。可以编辑/etc/ssh/sshd_config在文件末尾添加Match User root AuthenticationMethods keyboard-interactive这意味着当用户是root时只允许键盘交互式认证即强制走PAM的密码验证码流程即使他有公钥也会被要求输入验证码。这可以防止通过公钥直接登录root。4.2 应对服务器时间不同步问题TOTP严重依赖时间同步。如果服务器时间偏差超过允许的窗口默认前后30秒共90秒验证就会失败。检查时间date命令查看服务器时间与手机时间对比。启用并同步NTP# CentOS 7 sudo yum install ntp -y sudo systemctl enable ntpd sudo systemctl start ntpd sudo ntpdate -s time.apple.com # 手动同步一次 sudo systemctl restart ntpd # Ubuntu / CentOS 8 sudo timedatectl set-ntp true sudo systemctl restart systemd-timesyncd调整容错窗口如果因特殊原因无法保证精确时间同步可以在用户初始化时对“allow an extra token before and after”的问题回答y这已经提供了90秒窗口。极端情况下可以手动编辑.google_authenticator文件第一行密钥后的第一个数字就是窗口大小默认为1表示前后各1个窗口共3个。改为2则共5个窗口150秒。但扩大窗口会降低安全性不推荐。4.3 紧急情况的备份与恢复方案1. 紧急刮刮码 (Scratch Codes) 在运行google-authenticator时它会生成5个8位数字的紧急刮刮码。这些码是一次性的可以在你丢失手机时用于登录。请立即将它们打印出来或保存在安全的密码管理器里。登录时在要求输入验证码的地方直接输入一个刮刮码即可。2. 备份.google_authenticator文件 这是最根本的备份。加密后存储# 备份文件 tar -czf - ~/.google_authenticator | openssl enc -aes-256-cbc -pbkdf2 -out ga_backup.tar.gz.enc # 恢复时 openssl enc -d -aes-256-cbc -pbkdf2 -in ga_backup.tar.gz.enc | tar -xz -C ~/3. 多设备绑定 在初始化时密钥文本以otpauth://开头的URI或纯文本密钥可以同时添加到多个Authenticator App中如手机和备用平板。或者使用像Authy这类支持云同步端到端加密的验证器但需权衡云同步带来的潜在风险。4. 保留一个“逃生”账户或会话 在强制所有用户启用2FA前确保至少有一个管理账户配置了SSH公钥认证并且该公钥认证不受keyboard-interactive强制要求的影响即不在Match User或特定AuthenticationMethods限制内。这个账户可以作为最后的恢复手段。5. 常见问题与故障排查实录即使按照步骤操作也可能会遇到问题。以下是我在实践中遇到的高频问题及解决方法。5.1 登录时提示 “Permission denied (publickey,keyboard-interactive)”这是最常见的错误意味着SSH服务器拒绝了你的所有认证方法。可能原因1/etc/ssh/sshd_config中AuthenticationMethods配置错误。排查检查AuthenticationMethods行是否有语法错误如多余的逗号或空格。建议先将其注释掉行首加#重启sshd后测试密码登录是否恢复。然后逐项添加测试。可能原因2PAM配置模块顺序或控制标志错误。排查检查/etc/pam.d/sshd确保pam_google_authenticator.so行没有放在auth required pam_deny.so这类总是拒绝的模块之后。确保使用了nullok参数。可能原因3SELinux仅限RHEL系阻止PAM模块或文件访问。排查可以临时将SELinux设置为宽容模式测试sudo setenforce 0。如果此时登录成功则问题在此。需要为相关模块添加SELinux策略sudo audit2allow -a查看拒绝日志然后根据提示创建并应用新策略模块。更简单但安全性降低的方法是禁用SELinux对SSH的约束sudo setsebool -P sshd_full_access 1。5.2 不提示输入验证码直接密码错误或被拒绝可能原因1用户未成功运行google-authenticator家目录下没有.google_authenticator文件且PAM配置中没有nullok参数。解决登录其他账户为该用户创建文件或临时在PAM配置中添加nullok。可能原因2ChallengeResponseAuthentication设置为no。解决确认/etc/ssh/sshd_config中此项为yes。可能原因3SSH客户端不支持键盘交互式认证。一些老旧的客户端或自动化脚本可能有问题。解决使用较新的OpenSSH客户端7.3以上并在连接时添加-o PreferredAuthenticationskeyboard-interactive,password参数显式指定。5.3 验证码总是错误可能原因1服务器与手机时间不同步。这是99%的原因。解决如上文所述配置并同步NTP。在服务器上执行date与手机时间对比误差应在30秒内。可能原因2在Authenticator App中绑定错误。例如扫描二维码时网络延迟导致数据不完整或手动输入密钥时输错。解决重新运行google-authenticator使用-t -d -f -r 3 -R 30 -w 3参数可以非交互式地重新生成但会覆盖原有配置用新的密钥重新绑定。或者直接编辑.google_authenticator文件第一行就是密钥确保手机App输入的与之一致。可能原因3.google_authenticator文件权限或所有权错误。解决确保该文件位于对应用户的家目录权限为600所有者为该用户。ls -la ~/.google_authenticator检查。5.4 如何为大量用户批量部署手动为每个用户运行命令效率太低。可以写一个简单的脚本但必须注意安全因为密钥种子是明文。#!/bin/bash # 批量初始化脚本示例 (谨慎使用) USER_LISTuser1 user2 user3 BASE_OTP_KEYJBSWY3DPEHPK3PXP # 示例密钥实际应随机生成 for USER in $USER_LIST; do sudo -u $USER google-authenticator -t -d -f -r 3 -R 30 -w 3 -s /home/$USER/.google_authenticator EOF y y y y EOF # 上面的EOF部分回答了所有交互问题为yes # 然后你需要将密钥BASE_OTP_KEY用户盐安全地分发给相应用户 done更安全的生产环境做法是使用配置管理工具Ansible、SaltStack将预先为每个用户生成的密钥文件在安全的离线环境中生成分发到家目录并设置正确的权限。5.5 与其他认证方式的结合公钥2FA最安全的SSH登录方式是公钥 密码 二次验证。但通常我们使用“公钥 二次验证”。配置如下 在/etc/ssh/sshd_config中PubkeyAuthentication yes PasswordAuthentication no # 禁用密码强制使用公钥 ChallengeResponseAuthentication yes AuthenticationMethods publickey keyboard-interactive这样登录时客户端首先尝试公钥认证无需交互。公钥认证成功后触发keyboard-interactivePAM要求输入Google Authenticator验证码。验证通过登录成功。这种方式既利用了公钥加密的强度又增加了“拥有物”手机因子是目前服务器安全访问的黄金标准。整个配置过程从原理到实践再到排错和加固核心思想是在安全与便利之间取得平衡。启用二次验证后你的服务器SSH端口虽然依然暴露在互联网的“枪林弹雨”中但攻击者成功的概率已经降至极低。定期审查日志/var/log/secure或/var/log/auth.log你会看到那些持续的密码尝试在二次验证的关卡前无功而返这种安全感是单纯修改端口或使用复杂密码无法比拟的。最后再次强调任何涉及认证的修改务必保留一个有效的备用访问通道并在测试环境充分验证后再上生产。
返回列表