第5章 密码认证与多因素认证
第5章 密码认证与多因素认证
5.1 密码认证机制
虽然密钥认证更安全,但在某些场景下密码认证仍然需要:
- 首次部署密钥前的初始访问
- 临时用户/访客访问
- 企业合规要求
- 共享账户(不推荐,但现实存在)
密码认证工作流程
客户端 服务器
│ 发送用户名 ──────────────────────>│
│ │ 检查用户是否存在
│<── 要求密码认证 ──────────────────│
│ │
│ 发送密码(加密通道内)──────────>│
│ │ 验证密码(PAM 或 /etc/shadow)
│<── 认证成功/失败 ─────────────────│
sshd_config 密码相关配置
# /etc/ssh/sshd_config
# 启用密码认证
PasswordAuthentication yes
# 禁止空密码
PermitEmptyPasswords no
# 密码尝试次数(在 sshd_config 中由 MaxAuthTries 控制)
MaxAuthTries 3
# 登录宽限时间
LoginGraceTime 60
5.2 PAM(Pluggable Authentication Modules)
PAM 简介
PAM 是 Linux/Unix 系统的可插拔认证框架,它将认证逻辑与应用程序分离:
┌─────────────────────────────────────────┐
│ 应用程序 (sshd) │
├─────────────────────────────────────────┤
│ PAM API │
├──────┬──────┬──────┬──────┬─────────────┤
│ 认证 │ 账户 │ 密码 │ 会话 │ PAM 模块 │
│auth │account│passwd│session│ │
├──────┴──────┴──────┴──────┤ │
│ pam_unix.so │ pam_ldap.so │
│ pam_ldap.so │ pam_sss.so │
│ pam_google_authenticator.so│pam_duo.so │
│ pam_u2f.so │ ... │
└───────────────────────────┴─────────────┘
sshd 与 PAM 集成
# /etc/ssh/sshd_config
# 启用 PAM(默认通常为 yes)
UsePAM yes
注意: 在大多数 Linux 发行版上,
UsePAM yes是默认值且强烈建议保持。禁用 PAM 可能导致某些功能(如账户过期检查、session 管理)失效。
PAM 配置文件
# SSH 的 PAM 配置文件
# Debian/Ubuntu
cat /etc/pam.d/sshd
# RHEL/CentOS
cat /etc/pam.d/sshd
典型的 PAM 配置:
# /etc/pam.d/sshd (Debian/Ubuntu 示例)
# 核心认证模块
@include common-auth
# 账户管理(过期检查等)
account required pam_nologin.so
@include common-account
# 会话管理
session [success=ok ignore=ignore module_unknown=ignore default=bad] pam_selinux.so close
session required pam_loginuid.so
session optional pam_keyinit.so force revoke
@include common-session
# 密码管理
@include common-password
PAM 控制标志
| 标志 | 说明 |
|---|---|
required | 必须通过,失败后继续检查其他模块 |
requisite | 必须通过,失败后立即拒绝 |
sufficient | 通过即成功(前面无 required 失败) |
optional | 可选,不影响最终结果 |
include | 包含其他配置文件 |
5.3 密码策略强化
设置密码复杂度要求
# 安装密码质量检查模块
sudo apt install libpam-pwquality # Debian/Ubuntu
sudo yum install pam_pwquality # RHEL/CentOS
# 编辑 PAM 配置
# /etc/pam.d/common-password (Debian/Ubuntu)
# /etc/pam.d/system-auth (RHEL/CentOS)
password requisite pam_pwquality.so retry=3 minlen=12 dcredit=-1 ucredit=-1 lcredit=-1 ocredit=-1
参数说明:
| 参数 | 说明 |
|---|---|
retry | 允许重试次数 |
minlen | 最小密码长度 |
dcredit | 至少 N 个数字(负值=必须) |
ucredit | 至少 N 个大写字母 |
lcredit | 至少 N 个小写字母 |
ocredit | 至少 N 个特殊字符 |
账户锁定策略
# 安装 pam_faillock (RHEL/CentOS)
# 或 pam_tally2 (旧版系统)
# /etc/pam.d/sshd 添加:
# 认证失败锁定
auth required pam_faillock.so preauth silent deny=5 unlock_time=900
auth [default=die] pam_faillock.so authfail deny=5 unlock_time=900
account required pam_faillock.so
# 参数说明:
# deny=5 失败 5 次后锁定
# unlock_time=900 锁定 900 秒(15 分钟)
# 查看锁定状态
sudo faillock --user admin
# 手动解锁
sudo faillock --user admin --reset
登录时间限制
# /etc/pam.d/sshd
# 只允许工作时间登录(周一至周五 8:00-18:00)
account required pam_time.so
# /etc/security/time.conf
# sshd;*;admin;Wk0800-1800
# 格式:services;ttys;users;times
5.4 多因素认证(MFA)配置
TOTP(基于时间的一次性密码)
使用 Google Authenticator 或兼容应用(如 Authy、Microsoft Authenticator):
步骤一:安装 Google Authenticator PAM
# Debian/Ubuntu
sudo apt install libpam-google-authenticator
# RHEL/CentOS
sudo yum install google-authenticator
步骤二:配置 PAM
# /etc/pam.d/sshd
# 在文件开头添加
auth required pam_google_authenticator.so nullok
注意:
nullok表示没有配置 TOTP 的用户仍然可以通过密码登录。移除nullok将强制所有用户使用 MFA。
步骤三:配置 sshd
# /etc/ssh/sshd_config
# 启用键盘交互认证(TOTP 通过此通道)
KbdInteractiveAuthentication yes
ChallengeResponseAuthentication yes
# 设置认证方法顺序
AuthenticationMethods publickey,keyboard-interactive
# 或者只要求密码 + TOTP
AuthenticationMethods keyboard-interactive
# 注意:不要同时启用 PasswordAuthentication 和 KbdInteractiveAuthentication
# 会导致认证方式冲突
PasswordAuthentication no
步骤四:用户配置 TOTP
# 每个用户运行一次(通过 SSH 或本地终端)
google-authenticator
# 交互过程:
# Do you want authentication tokens to be time-based (y/n) y
# [显示 QR 码和密钥]
# Your new secret key is: JBSWY3DPEHPK3PXP
# [用手机扫描 QR 码]
#
# Enter code from app (-1 to skip): [输入手机上显示的 6 位数字]
#
# Do you want me to update your file? (y/n) y
# Do you want to disallow multiple uses? (y/n) y
# Do you want to increase time window? (y/n) n
# Do you want to enable rate-limiting? (y/n) y
生成的配置文件:
# ~/.google_authenticator
# [密钥]
# [5 个紧急备用码]
# " RATE_LIMIT 3 30
# " WINDOW_SIZE 17
# " DISALLOW_REUSE 5432101
# " TOTP_AUTH
验证 TOTP 配置
# 从另一个终端测试连接(保持当前终端不要关闭!)
ssh user@server
# 输入密码后,应该会提示输入验证码
# Verification code: [输入 6 位 TOTP]
TOTP 完整配置示例
# /etc/ssh/sshd_config
# TOTP MFA 配置
UsePAM yes
PasswordAuthentication no
KbdInteractiveAuthentication yes
AuthenticationMethods publickey,keyboard-interactive
# 为不同用户设置不同认证方法
Match User admin
AuthenticationMethods publickey,keyboard-interactive
Match User guest
AuthenticationMethods keyboard-interactive
PasswordAuthentication yes
Match User deploy
AuthenticationMethods publickey
U2F/FIDO2 硬件密钥
OpenSSH 8.2+ 支持 FIDO2/U2F 硬件密钥(如 YubiKey、SoloKey):
# 生成 FIDO2 密钥
ssh-keygen -t ed25519-sk -O resident -f ~/.ssh/id_ed25519_sk
# -t ed25519-sk 使用 Ed25519 + FIDO2 安全密钥
# -O resident 保存密钥句柄到硬件密钥(可跨设备使用)
# -O verify-required 需要触摸/生物认证
# 部署公钥到服务器(与普通公钥相同)
ssh-copy-id -i ~/.ssh/id_ed25519_sk.pub user@server
# 连接时需要触摸硬件密钥
ssh user@server
# 触摸你的安全密钥...
Duo Security 集成
# 安装 Duo Unix
# 参考 Duo 官方文档
# /etc/pam.d/sshd
auth required pam_duo.so
# /etc/duo/pam_duo.conf
[duo]
ikey = YOUR_INTEGRATION_KEY
skey = YOUR_SECRET_KEY
host = api-XXXXXXXX.duopublic.com
pushinfo = yes
autopush = yes
5.5 认证方法组合
AuthenticationMethods 支持多种组合方式:
# 多因素:先公钥,再键盘交互(密码/TOTP)
AuthenticationMethods publickey,keyboard-interactive
# 多因素:先公钥,再密码
AuthenticationMethods publickey,password
# 单因素:只要公钥
AuthenticationMethods publickey
# 单因素:只要密码
AuthenticationMethods password
# 两种方式都接受(任选其一)
AuthenticationMethods publickey password
# 注意:逗号 = AND(多因素),空格 = OR(任选)
| 语法 | 含义 |
|---|---|
publickey,keyboard-interactive | 公钥 AND 键盘交互(多因素) |
publickey keyboard-interactive | 公钥 OR 键盘交互(单因素) |
publickey,password | 公钥 AND 密码(多因素) |
publickey password | 公钥 OR 密码(单因素) |
为不同用户设置不同认证方法
# /etc/ssh/sshd_config
# 默认:公钥认证
AuthenticationMethods publickey
# 管理员:公钥 + TOTP
Match User admin
AuthenticationMethods publickey,keyboard-interactive
PasswordAuthentication no
KbdInteractiveAuthentication yes
# 部署用户:仅公钥
Match User deploy
AuthenticationMethods publickey
ForceCommand /opt/deploy/deploy.sh
# 临时访客:密码 + TOTP
Match Group visitors
AuthenticationMethods keyboard-interactive
PasswordAuthentication yes
ChrootDirectory /home/visitor
5.6 常见问题排查
问题一:PAM 认证失败
# 调试 PAM
# /etc/ssh/sshd_config
LogLevel VERBOSE
# 查看 PAM 日志
sudo journalctl -u sshd | grep -i pam
# 手动测试 PAM 认证
sudo pamtester sshd admin authenticate
问题二:TOTP 不接受验证码
# 常见原因:时间不同步
# 检查服务器时间
timedatectl status
# 同步时间
sudo timedatectl set-ntp true
sudo systemctl restart systemd-timesyncd
# 验证时间同步
chronyc tracking
问题三:Google Authenticator 配置后无法登录
# 确保 PAM 配置正确
cat /etc/pam.d/sshd | grep google_authenticator
# 确保用户配置了 TOTP
ls -la ~/.google_authenticator
# 文件权限
chmod 400 ~/.google_authenticator
chmod u+r ~/.google_authenticator
问题四:AuthenticationMethods 冲突
# 错误信息:
# userauth_pubkey: parse AuthenticationMethods: unexpected methods
# 确保语法正确:
# 逗号 = AND,空格 = OR
AuthenticationMethods publickey,keyboard-interactive # ✅
AuthenticationMethods publickey keyboard-interactive # ✅ (注意是两种方案)
5.7 从密码认证迁移到密钥认证
迁移步骤
# 步骤 1:部署所有用户的公钥
# 使用 Ansible 批量部署
ansible all -m authorized_key -a \
"user=admin key='{{ lookup(\"file\", \"~/.ssh/id_ed25519.pub\") }}'"
# 步骤 2:验证密钥认证可用
ssh -o PreferredAuthentications=publickey admin@server "echo 'Key auth works!'"
# 步骤 3:设置宽限期(先通知用户)
# 在 /etc/ssh/sshd_config 中临时设置:
# PasswordAuthentication yes
# Banner /etc/ssh/warning.txt
# /etc/ssh/warning.txt 内容:
# WARNING: 密码认证将在 2025-02-01 禁用。
# 请尽快配置 SSH 密钥认证。
# 步骤 4:禁用密码认证
# 确认所有用户都已配置密钥后
PasswordAuthentication no
KbdInteractiveAuthentication no
# 步骤 5:重新加载配置
sudo systemctl reload sshd
扩展阅读
下一章: 第6章 sshd_config 深入解析 → 全面掌握 SSH 服务器配置文件的每个参数和 Match 块。