强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

SSH 服务器完全指南 / 第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 块。