必须使用pam_pwquality.so(现代系统)或pam_cracklib.so(旧系统)配置ucredit=-1、lcredit=-1、dcredit=-1、ocredit=-1来强制密码含大小写字母、数字和特殊符号;/etc/login.defs中的pass_min_len无效,真正生效的是pam的minlen参数。

怎么让密码必须含大小写字母、数字和特殊符号
核心是用 pam_pwquality.so 或旧版 pam_cracklib.so 模块强制校验字符类型。现代发行版(RHEL 8+/CentOS 8+/Ubuntu 20.04+)默认用 pam_pwquality,它更稳定、参数语义更清晰。
-
ucredit=-1:至少 1 个大写字母;lcredit=-1:至少 1 个小写字母 -
dcredit=-1:至少 1 个数字;ocredit=-1:至少 1 个特殊字符(如!@#$%) - 别混用
pam_cracklib.so和pam_pwquality.so—— 两者不能共存于同一行,否则策略可能静默失效 - 如果改的是
/etc/pam.d/system-auth,注意该文件常被其他 PAM 配置 include,优先检查是否有重复加载导致冲突
为什么改了 /etc/login.defs 却没生效
PASS_MIN_LEN 这类参数只对未启用 PAM 密码模块的极简环境起作用;一旦系统加载了 pam_pwquality 或 pam_cracklib,它就完全被忽略 —— 这是最多人踩的坑。
-
PASS_MAX_DAYS 90、PASS_WARN_AGE 7这类时间策略仍有效,它们控制chage和 shadow 数据库行为 -
PASS_MIN_LEN值设再大也没用,真正起效的是minlen=12这类 PAM 参数 - 验证方式:运行
passwd修改普通用户密码,故意输一个纯字母的短密码,看是否被拒绝 —— 不要只看配置文件有没有改对
如何防止用户反复用同一个旧密码
靠 pam_unix.so 的 remember=5 参数,它会把旧密码 hash 存进 /etc/security/opasswd,但前提是该行必须在 PAM 链中正确位置且未被跳过。
- 在
/etc/pam.d/common-password(Debian/Ubuntu)或/etc/pam.d/system-auth(RHEL/CentOS)里找含pam_unix.so的password行 - 追加
remember=5,并确保它和sha512、shadow等选项在同一行,例如:password [success=1 default=ignore] pam_unix.so obscure sha512 shadow nullok remember=5 - 首次启用后,
/etc/security/opasswd是空的,需等用户改过一次密码才会生成记录;root 用户默认不记历史,加enforce_for_root才生效
测试时密码总被拒绝,但配置看起来没问题
常见真因不是参数写错,而是模块加载顺序或条件判断逻辑被绕过了。PAM 是按行执行的,requisite 失败直接终止,sufficient 成功则跳过后续 —— 很多问题出在这里。
- 确认你改的是「正在被实际调用」的配置文件:SSH 登录走
/etc/pam.d/sshd,本地终端走/etc/pam.d/login,而它们通常 includesystem-auth或common-password -
minlen=12在pam_pwquality中真值是「12 字符」,但在老版pam_cracklib中实际生效长度是minlen - 1(即设 12 实际要求 11),这点文档极少明说 - 临时加
debug参数(如password [default=ok] pam_pwquality.so debug)可查/var/log/secure里的具体拒绝原因
最麻烦的点在于:不同发行版默认用的模块不同、路径不同、甚至同一模块的参数兼容性也不同 —— RHEL 9 已弃用 pam_cracklib,但某些定制镜像还在用,得先 ls /lib64/security/ | grep -E "(pwquality|cracklib)" 确认现场到底加载了哪个。










