Ubuntu 24.04 SSH 二次验证配置指南(Google Authenticator TOTP)
服务器暴露在公网上,每天被脚本扫描几千次是常态。密码再复杂也扛不住暴力破解、撞库、0day 组合拳。给 SSH 加上 TOTP 二次验证(也就是 Google Authenticator 那套 6 位动态码),相当于给大门上了第二把锁——即使密码泄露,没有手机上的码也进不来。
本文覆盖三种场景,从简单到严格,你自己选:
一、基础方案:密码 + TOTP 二次验证
适合个人服务器,保留密码登录,每次额外输一次 6 位验证码。
1.1 安装 PAM 模块
sudo apt update
sudo apt install -y libpam-google-authenticator
验证安装:
ls /lib/security/pam_google_authenticator.so
有输出即成功。
1.2 为当前用户生成密钥
务必用你要登录的普通用户执行,不要用 root。
google-authenticator
它会依次提问,全部选 y:
| 问题 | 选 y 的含义 |
|---|---|
| Time-based tokens? | 使用基于时间的验证码(TOTP) |
| Update ~/.google_authenticator? | 保存密钥到用户目录 |
| Disallow multiple uses? | 同一验证码只能用一次 |
| Tokens valid for 30 seconds? | 窗口期内是否允许前后偏移一次(选 y 更安全) |
| Enable rate-limiting? | 限制每 30 秒最多尝试 3 次 |
执行完成后,终端会显示两样东西:
- 二维码 — 用手机 Google Authenticator 扫描
- 紧急备用码(backup codes) — 一定要抄下来保存好,手机丢了靠这个救命
1.3 配置 SSH PAM
sudo nano /etc/pam.d/sshd
在文件末尾添加一行:
auth required pam_google_authenticator.so
保存退出(Ctrl+O → Enter → Ctrl+X)。
1.4 开启 SSH ChallengeResponse
sudo nano /etc/ssh/sshd_config
确保以下两项为 yes:
ChallengeResponseAuthentication yes
UsePAM yes
Ubuntu 24.04 中
ChallengeResponseAuthentication已重命名为KbdInteractiveAuthentication,两者作用相同。如果有KbdInteractiveAuthentication项也一并确认开启。
保存后重启 sshd:
sudo systemctl restart sshd
1.5 手机端配置
手机安装 Google Authenticator(App Store / 各应用商店可搜到)→ 点 + → 扫描二维码 → 出现 6 位数字,每 30 秒变一次。
1.6 测试登录
新开一个终端窗口:
ssh user@你的服务器IP
会依次提示:
Password: # 输入密码
Verification code: # 输入手机上的 6 位数字
两步都通过即登录成功。测试完不要关掉当前会话,确保一切正常再断开。
二、进阶方案:仅指定用户启用 2FA
如果服务器上有多个用户,但只想给特定账号(比如你常用的管理员用户)加上二次验证,可以用 pam_succeed_if 做条件判断。
2.1 需要 2FA 的用户各自生成密钥
每个需要开启 2FA 的用户自己登录执行:
google-authenticator
# 全部选 y,保存备用码,手机扫码
2.2 修改 PAM 配置加判断规则
sudo nano /etc/pam.d/sshd
注释掉之前的全局启用行,添加条件判断:
# auth required pam_google_authenticator.so # 注释掉这一行(全局启用)
# 仅 user1、user2 启用二次验证,其余用户跳过
auth [success=1 default=ignore] pam_succeed_if.so user in user1:user2
auth required pam_google_authenticator.so nullok
把 user1:user2 换成你要开启 2FA 的用户名,冒号分隔。
nullok 参数的作用:如果名单内的用户还没执行 google-authenticator 生成密钥,暂时跳过验证,不会直接锁住。
2.3 确认 SSH 配置并重启
sudo nano /etc/ssh/sshd_config
# 确保有:
# KbdInteractiveAuthentication yes
# UsePAM yes
sudo systemctl restart sshd
2.4 效果
- 名单内用户登录:密码 + 6 位验证码
- 名单外用户:只输密码,直接登录
三、最优方案:SSH 密钥 + TOTP 双因子(无密码)
这是生产服务器的推荐配置——彻底禁用密码登录,必须同时持有 SSH 私钥 + 手机 TOTP 验证码才能登录。暴力破解直接无效。
3.1 编辑 SSH PAM
sudo nano /etc/pam.d/sshd
清空原有 2FA 配置,写入:
# 关闭密码登录认证
auth required pam_deny.so
# 开启 2FA 动态验证码校验
auth required pam_google_authenticator.so
3.2 修改 SSH 主配置
sudo nano /etc/ssh/sshd_config
设置以下参数:
# 启用键盘交互验证(2FA 必备)
KbdInteractiveAuthentication yes
# 启用 PAM 模块
UsePAM yes
# 允许密钥登录
PubkeyAuthentication yes
# 彻底禁用账号密码登录(核心)
PasswordAuthentication no
ChallengeResponseAuthentication no
3.3 限制仅指定用户可登录(推荐)
在 sshd_config 末尾添加:
AllowUsers 你的用户名1 用户名2
3.4 精准区分:指定用户走密钥+2FA,其他人拒绝
修改 /etc/pam.d/sshd:
# 仅指定用户走 2FA 流程
auth [success=1 default=deny] pam_succeed_if.so user in root:ubuntu
auth required pam_google_authenticator.so
把 root:ubuntu 换成你的用户名,冒号分隔。不在列表里的用户直接被 default=deny 拒绝,连密钥认证的机会都没有。
3.5 重启生效
sudo systemctl restart sshd
3.6 客户端登录流程
ssh 用户名@服务器IP
过程:
1. SSH 私钥自动校验(通过)
2. 弹出提示 → Verification code:
3. 输入手机 6 位动态码
4. 登录成功
没有私钥 → 连接被拒绝 有私钥但没有验证码 → 卡在第二步进不去
四、关键说明:2FA 只拦 SSH,不影响网站
这是很多人配置时的最大顾虑——「我开了 SSH 二次验证,会不会把网站搞挂了?」
完全不会。 2FA 只拦截远程 SSH 登录这一个入口,和网站运行是两个完全独立的层面。
| 场景 | 会不会受影响 | 原因 |
|---|---|---|
| 游客访问网页 | 不受影响 | 走 nginx 端口(80/443),不经过 sshd |
| API 接口调用 | 不受影响 | 同样走 nginx,和 SSH 无关 |
| 网站后台登录 | 不受影响 | 属于网站自身登录,和 SSH 二次验证彻底分离 |
| www-data / nginx / apache 用户运行进程 | 不受影响 | 系统服务用户不需要 SSH 登录 |
| PHP/Python 程序进程 | 不受影响 | 正常运行,无任何权限拦截 |
| SFTP / rsync 同步 | 不受影响 | 走 SSH 子系统的不需要 2FA(取决于配置) |
实际做法是:用 AllowUsers 或 pam_succeed_if 把 2FA 限制在运维账号(如 root、webadmin),系统服务用户(www-data、nginx 等)压根没有 SSH 登录的必要,也不需要生成 2FA 密钥。示例:
# 仅允许运维账号 SSH 登录
AllowUsers root webadmin
# PAM 中仅这两个账号需要 2FA
auth [success=1 default=ignore] pam_succeed_if.so user in webadmin:root
auth required pam_google_authenticator.so nullok
简单说:2FA 只拦人,不拦网站。
五、应急方案(手机丢失 / 验证码失效)
手机丢了或验证码一直不对:
- 通过服务器本地控制台(VPS 商家的 Web VNC / IPMI)登录账号
- 删除 2FA 配置文件:
rm ~/.google_authenticator
- 删除后即可直接登录(绕过验证)
- 重新执行
google-authenticator绑定新手机
备份码的作用:手机丢了但还有服务器 SSH 会话没断的话,可以用备份码登录。但最稳妥的方案永远是去控制台删文件。
六、常见问题
Q:只想给部分用户启用 2FA?
→ 用方案二的 pam_succeed_if 条件判断。
Q:root 也想启用?
→ root 登录后执行 google-authenticator,其他步骤一样。
Q:备份码和手机都丢了?
→ 去服务器本地控制台删 ~/.google_authenticator 文件,重新绑定。
Q:重启 sshd 后连不上了?
→ 通过 VPS 商家提供的 Web VNC / 控制台登录排查,最常见原因是 pam.d/sshd 配置语法错误。
Q:已经有用户在登录中,配置会不会踢掉他们?
→ sshd 重启不影响已建立的连接。但你测试时一定要保留一个已登录的会话,新窗口测试通过再退出。
七、总结
三种方案对比如下:
| 方案 | 密码 | SSH 密钥 | TOTP 验证码 | 适合场景 |
|---|---|---|---|---|
| 基础方案 | ✅ | ❌ | ✅ | 个人服务器、低风险 |
| 进阶方案(指定用户) | ✅ | ❌ | ✅(仅指定用户) | 多人服务器、分权限 |
| 最优方案(推荐) | ❌ | ✅ | ✅ | 生产服务器、云服务器 |
对于面向公网的服务器,最优方案是唯一合理的选择——密码是最大的攻击面,关掉它就关掉了 99% 的脚本扫描。
如果你对 Google Authenticator 的隐私顾虑(它会上传数据),推荐替代品:
- Aegis(Android,开源,本地存储)
- Raivo OTP(iOS,开源)
- Bitwarden(内置 TOTP,全平台)
- 2FAS(全平台,开源)
以上 App 都兼容 Google Authenticator 的 TOTP 标准,扫描同一个二维码即可。
原文发表于 cn-res.vip