TOTP是离线MFA唯一可行选择,因其不依赖网络、仅靠本地时钟与密钥计算;而HOTP因计数器同步问题在离线场景不可用。

为什么 totp 是离线 MFA 的唯一可行选择
离线环境没法连 Google Authenticator 服务器或短信网关,所以必须用时间同步型令牌(TOTP)——它不依赖网络,只靠设备时钟和密钥本地计算。RFC 6238 定义的 totp 算法在服务端和客户端用同一密钥+当前时间窗口(默认30秒)生成6位数字,双方独立算,结果一致就通过。
别碰 hotp(基于计数器),它要求服务端严格维护并同步计数器值,离线场景下一旦客户端多按一次、服务端没收到验证请求,计数器就错位,后续全挂;重置成本高,且无法自动恢复。
-
totp密钥必须用 base32 编码(如JBQWY3DPEHPK3PXP),不能直接存明文或 hex - 服务端时间必须和 NTP 同步,误差超过 1.5 个时间窗口(即 45 秒)就会频繁失败,
systemd-timesyncd或chrony要常驻运行 - 客户端首次配对时,允许前后两个时间窗口(±1 分钟)校验,但上线后建议锁死为仅当前窗口,防重放
Linux 服务器上启用 pam_google_authenticator 的最小安全配置
Debian/Ubuntu 默认源里的 pam_google_authenticator 模块最成熟,但开箱即用不等于安全:它默认允许「备用验证码」、不限制尝试次数、不绑定 IP,离线部署时这些都得手动关掉。
编辑 /etc/pam.d/sshd,在 @include common-auth 前插入:
auth [required] pam_google_authenticator.so secret=/home/${USER}/.google_authenticator user=root forward_pass noskewadj
-
secret=必须指向用户家目录下的.google_authenticator文件,不能全局共享;root 用户需单独生成 -
noskewadj关闭自动时钟偏移补偿——离线服务器若时间不准,应修时间而非让 PAM 将就 - 删掉模块参数里的
remember=10和allowed_attempts=3(它们无效),实际限速靠pam_faildelay.so或 SSH 的MaxAuthTries - 生成密钥时用
google-authenticator -t -d -f -w 3 -e 10:-t强制 TOTP,-d禁用二维码(离线环境扫不了),-w 3只存最近3个备用码(够应急,不多留)
sshd_config 里开启 MFA 的关键三行不能少
光配 PAM 不够,SSH daemon 必须明确告诉客户端:“你得填两个东西——密码 + 6位码”。这靠 AuthenticationMethods 控制,不是简单打开 ChallengeResponseAuthentication yes 就完事。
在 /etc/ssh/sshd_config 中确认以下三行存在且未被注释:
AuthenticationMethods keyboard-interactive:pam,publickey<br>KbdInteractiveAuthentication yes<br>PubkeyAuthentication yes
- 顺序很重要:
keyboard-interactive:pam必须放在publickey后面,否则公钥直通,MFA 形同虚设 - 不能写成
keyboard-interactive(漏掉:pam),那会触发 SSH 自带的过时 challenge-response 流程,和 PAM 模块不对接 - 如果用密码登录(非密钥),要把
keyboard-interactive:pam改成password,keyboard-interactive:pam,但强烈建议禁用密码,只留密钥 + TOTP
用户密钥文件 .google_authenticator 的权限和分发风险
这个文件里存着 base32 密钥、时间偏移、备用码,一旦泄露,攻击者立刻能生成有效令牌。离线环境没有中央密钥管理,全靠人工分发和保护,出错就是全线失守。
- 文件权限必须是
600(chmod 600 ~/.google_authenticator),属主必须是对应用户,root不能拥有它 - 生成后立即删掉终端输出的密钥原文和二维码文本——很多管理员复制完就留在 shell 历史里,
history -c不够,还得清~/.bash_history - 备用码要打印出来手写存档,别存电子文档;每用一个就划掉一个,用完立即重生成密钥
- 别用脚本批量部署密钥——每个用户必须有独立密钥,共用等于单点击穿
时钟漂移、密钥权限、PAM 配置顺序,这三个地方出问题,90% 的“MFA 不生效”就在这里卡住。其他都是锦上添花,先盯死这三处。










