在Ubuntu系统中,通过libpam模块配置密码复杂度和密码历史记录,核心操作就是编辑/etc/pam.d/common-password文件,利用pam_pwquality或pam_cracklib模块设定最小长度、字符类型、重复字符限制,再通过pam_unix模块的remember参数控制密码历史记录条数。这套配置直接决定了系统用户密码的安全强度,是Linux服务器安全加固的基础操作之一。
很多运维人员在部署Ubuntu服务器时,默认的密码策略过于宽松——允许6位纯数字密码、不记录历史密码、用户可以反复使用旧密码。这种配置在生产环境中是严重的安全隐患。下面我会从模块原理、具体配置、验证方法三个层面,把这件事彻底讲清楚。
一、libpam模块体系与密码策略的关系PAM(Pluggable Authentication Modules,可插拔认证模块)是Linux系统认证的核心框架。Ubuntu中所有与密码相关的策略,都集中在/etc/pam.d/目录下的配置文件中,其中common-password是控制密码修改行为的主文件。当用户执行passwd命令修改密码时,系统会依次加载这个文件中定义的模块,每个模块负责一项检查。
目前Ubuntu 18.04及以后的版本,默认使用pam_pwquality模块来替代老版本的pam_cracklib。pam_pwquality是libpwquality库的PAM前端,功能更强、配置更灵活。它负责检查密码的复杂度,比如长度、大小写、数字、特殊字符等。而密码历史记录则由pam_unix模块的remember参数来控制,它决定系统记住多少个旧密码,防止用户循环使用。
理解这个架构很重要:pam_pwquality管"密码够不够复杂",pam_unix管"旧密码能不能重用"。两者配合,才能构成完整的密码策略。
二、配置密码复杂度的具体方法打开配置文件进行编辑:
sudo nano /etc/pam.d/common-password
你会看到类似这样的内容:
password requisite pam_pwquality.so retry=3 password [success=1 default=ignore] pam_unix.so obscure use_authtok try_first_pass sha512
关键在第一行的pam_pwquality.so。这个模块支持大量参数,下面逐一说明核心参数的含义和推荐值:
minlen=12——密码最小长度。生产环境建议至少12位,如果是高安全场景可以设为14或16。默认值通常是8,远远不够。
dcredit=-1——要求至少包含1个数字。负数表示"至少需要这么多个",正数表示"最多允许这么多个"。设为-1就是至少1位数字。
ucredit=-1——至少包含1个大写字母。
lcredit=-1——至少包含1个小写字母。
ocredit=-1——至少包含1个特殊字符(如!@#$%等)。
maxrepeat=3——同一个字符最多连续重复3次。防止用户设置像"aaaabbb123"这种弱密码。
difok=5——新密码与旧密码至少要有5个字符不同。这个参数非常关键,防止用户只改一个字符就"换"了密码。
minclass=4——密码中必须包含至少4种字符类型(大写、小写、数字、特殊字符)。设为4就是全部都要有。
把这些参数组合起来,推荐的生产环境配置如下:
password requisite pam_pwquality.so retry=3 minlen=12 dcredit=-1 ucredit=-1 lcredit=-1 ocredit=-1 maxrepeat=3 difok=5 minclass=4
retry=3表示用户有3次输入机会,如果3次都不满足复杂度要求,passwd命令会报错退出。这个值不建议设太高,否则用户体验差;也不要设为1,给用户一点容错空间。
三、配置密码历史记录的具体方法密码历史记录的配置在同一文件的第二行,即pam_unix.so那一行。核心参数是remember:
remember=10——系统记住最近10个密码,用户不能重用这10个中的任何一个。Ubuntu默认通常是5,建议生产环境设为10到24之间。
如果你想同时控制"记住多少个"和"密码多久过期后才计入历史",还需要配合/etc/login.defs中的设置:
sudo nano /etc/login.defs
找到以下参数:
PASS_MAX_DAYS 90 PASS_MIN_DAYS 1 PASS_WARN_AGE 14
PASS_MAX_DAYS=90表示密码最长90天必须更换。PASS_MIN_DAYS=1表示两次修改密码之间至少间隔1天。PASS_WARN_AGE=14表示密码过期前14天开始提醒用户。这些参数和pam_unix的remember参数协同工作,构成完整的密码生命周期管理。
完整的pam_unix配置建议写成:
password [success=1 default=ignore] pam_unix.so obscure use_authtok try_first_pass sha512 remember=10
注意sha512表示使用SHA-512哈希算法存储密码,比老旧的md5安全得多。obscure参数会在输入密码时不回显,增加安全性。use_authtok和try_first_pass是为了让pam_pwquality检查通过后的密码能直接传给pam_unix,避免用户输入两次。
四、Ubuntu 22.04及更新版本的注意事项Ubuntu 22.04开始,系统默认启用了pam_pwquality的dictpath参数,指向一个字典文件/usr/share/dict/american-english。这意味着系统会检查密码是否是字典中的单词,防止用户使用"password""welcome"这类常见词。如果你的系统需要支持多语言,可以更换字典文件路径,或者直接禁用:
password requisite pam_pwquality.so retry=3 dictpath=
把dictpath设为空就禁用了字典检查。但从安全角度,建议保留字典检查,这是防止字典攻击的有效手段。
另外,Ubuntu 22.04还引入了pam_pwquality的enforcing参数,默认是1(强制执行)。如果设为0,模块只会给出警告但不阻止设置弱密码。生产环境绝对不要设为0。
五、配置完成后的验证方法配置改完之后,最直接的验证方式就是尝试设置一个弱密码,看系统是否拒绝:
sudo passwd testuser
尝试输入"123456"或者"password123",如果配置正确,系统应该提示密码不满足复杂度要求并要求重新输入。连续尝试3次后会报错退出。
验证密码历史记录可以这样操作:先给testuser设一个密码,然后尝试把密码改回原来的值,系统应该拒绝并提示"密码已在历史记录中"。
还可以用pam_tally2或faillock模块查看登录失败记录,确认整个认证链路正常:
sudo faillock --user testuser
这个命令会显示用户的失败登录次数和锁定状态,间接验证PAM配置是否生效。
六、常见问题与避坑指南第一个常见坑:修改/etc/pam.d/common-password后,不要直接用passwd root测试,万一配置出错导致root无法登录就麻烦了。建议先开一个终端窗口保持root会话,再开另一个窗口测试,或者先用普通用户测试。
第二个坑:如果系统同时安装了pam_cracklib和pam_pwquality,可能会产生冲突。Ubuntu 18.04之后默认只有pam_pwquality,但如果你从旧版本升级过来,检查一下是否有残留配置。可以用以下命令查看:
grep -r "pam_cracklib" /etc/pam.d/
第三个坑:某些应用程序(如MySQL、FTP服务)有自己独立的密码策略配置,不受PAM控制。PAM只管理系统用户的passwd命令,不要以为配了PAM就万事大吉,服务层面的密码策略要单独检查。
第四个坑:如果你使用SSH密钥登录而不是密码登录,PAM的密码复杂度策略对你不生效。但这不代表可以忽略,因为系统本地登录、sudo提权、单用户模式恢复都还是走密码认证的。
七、进阶建议:结合其他安全措施形成纵深防御密码复杂度和历史记录只是安全加固的一环。建议同时部署以下措施:限制root远程登录、配置fail2ban自动封禁暴力破解IP、启用双因素认证(如libpam-google-authenticator)、定期审计/etc/shadow文件权限确保只有root可读。这些措施和PAM密码策略组合在一起,才能构建真正有韧性的安全体系。
从合规角度看,等保2.0三级要求密码长度不低于8位且包含多种字符类型,PCI DSS要求密码至少7位且90天更换。本文推荐的12位+10条历史+90天过期的配置,已经超过了大多数合规标准的基线要求。
总结一下:Ubuntu的密码安全策略配置并不复杂,核心就是改好/etc/pam.d/common-password这一个文件。把pam_pwquality的参数设到位,把pam_unix的remember设到10以上,配合/etc/login.defs的过期策略,你的Ubuntu服务器密码安全就能达到生产级别。花十分钟配置,能挡住绝大多数基于弱密码的攻击,这是性价比极高的安全投入。
