Ubuntu系统中,用户密码哈希值存储在/etc/shadow文件里,默认的密码轮换周期是99999天(约273年),但这并不意味着你可以永远不换密码。实际生产环境中,安全合规要求通常强制设定为90天或180天轮换一次。要修改这个周期,核心操作就是编辑/etc/login.defs文件中的PASS_MAX_DAYS、PASS_MIN_DAYS、PASS_WARN_AGE三个参数,配合chage命令对具体用户进行精细化管理。下面我把整个机制、配置方法、实操步骤和安全建议一次性讲透。
一、Ubuntu shadow文件的密码哈希机制到底是什么
Ubuntu(以及所有基于Linux的系统)把用户密码的哈希值存在/etc/shadow文件中,这个文件只有root权限才能读取。每一行对应一个用户,字段用冒号分隔,典型格式如下:
username:$6$salt$hashvalue:19000:0:99999:7:::
其中第三个字段是密码哈希($6$表示SHA-512加密),第四个字段是"上次修改密码距1970年1月1日的天数",第五个字段是两次修改之间的最小间隔天数,第六个字段是最大有效天数,第七个字段是过期前的警告天数。第六个字段就是我们常说的"密码轮换周期"的核心控制项。默认99999天,意味着密码几乎永不过期。
二、为什么默认99999天是个安全隐患
从技术角度看,99999天的默认值是为了避免用户频繁被强制改密码导致体验差。但从安全角度,这是一个巨大的风险敞口。如果某个用户的密码在一次数据泄露中被窃取,攻击者拿到的哈希值可以无限期地进行离线暴力破解。尤其是当硬件算力不断提升、彩虹表不断更新的今天,一个弱密码的哈希可能在几小时内就被破解。
更关键的是,很多企业安全审计标准(如等保2.0、ISO 27001、CIS Benchmark)都明确要求密码最长有效期不超过90天。Ubuntu默认不强制轮换,等于把合规责任完全推给了管理员。所以,手动配置合理的轮换周期是每一个运维人员的基本功。
三、修改全局密码轮换周期的具体方法
全局配置文件是/etc/login.defs,用任何文本编辑器打开:
sudo vim /etc/login.defs
找到以下三个关键参数并修改:
PASS_MAX_DAYS 90 PASS_MIN_DAYS 1 PASS_WARN_AGE 7
PASS_MAX_DAYS设为90,表示密码最长90天必须更换;PASS_MIN_DAYS设为1,表示两次改密码之间至少间隔1天(防止用户连续改回旧密码);PASS_WARN_AGE设为7,表示过期前7天开始提醒用户。这三个值是业界比较通用的安全配置。如果你的环境安全等级更高,可以把PASS_MAX_DAYS改成60甚至30。
修改完保存后,新策略对之后新建的用户立即生效。但对已有用户,需要额外用chage命令逐个设置。
四、用chage命令对单个用户设置轮换策略
chage是专门管理用户密码过期策略的工具,比直接改shadow文件安全得多。查看某个用户当前的密码策略:
sudo chage -l username
输出示例:
Last password change : May 15, 2025 Password expires : Aug 13, 2025 Password inactive : never Account expires : never Minimum number of days between password change : 1 Maximum number of days between password change : 90 Number of days of warning before password expires : 7
如果要强制某个用户立即改密码并设置90天周期:
sudo chage -M 90 -m 1 -W 7 -d $(date +%Y-%m-%d) username
参数说明:-M是最大天数,-m是最小间隔天数,-W是警告天数,-d是强制上次修改日期设为今天(这样用户下次登录就必须改密码)。如果要批量处理所有用户,可以写个脚本:
for user in $(awk -F: '$3 >= 1000 {print $1}' /etc/passwd); do
sudo chage -M 90 -m 1 -W 7 "$user"
done这个脚本会把所有UID大于等于1000的普通用户(即非系统账户)都设置成90天轮换周期。
五、密码哈希算法的选择同样重要
光设轮换周期还不够,哈希算法本身的强度直接决定了密码被破解的难度。Ubuntu默认使用SHA-512($6$),这已经是比较强的算法了。但如果你的系统比较老,可能还在用MD5($1$)或DES(传统crypt),这些都应该淘汰。
检查系统支持的哈希算法:
sudo authconfig --test | grep hashing
如果需要强制使用SHA-512,编辑/etc/pam.d/common-password,找到类似这样的行:
password [success=1 default=ignore] pam_unix.so sha512
确保sha512参数存在。如果你想更进一步,可以考虑引入bcrypt或Argon2,但这需要额外安装libpam-argon2或libpam-bcrypt包,并且要注意兼容性问题。
六、shadow文件权限和审计不可忽视
/etc/shadow文件的权限必须是640或600,属主是root,属组是shadow。如果权限被错误地改成了644甚至更开放,任何普通用户都能读取所有密码哈希,后果不堪设想。定期检查:
ls -l /etc/shadow
正常输出应该是:
-rw-r----- 1 root shadow 1234 Jun 1 10:00 /etc/shadow
另外,建议开启auditd审计,监控shadow文件的访问行为:
sudo auditctl -w /etc/shadow -p rw -k shadow_access
这样任何对shadow文件的读写操作都会被记录到/var/log/audit/audit.log中,方便事后追溯。
七、自动化轮换和PAM集成方案
对于服务器数量多的环境,手动chage显然不现实。可以通过PAM模块pam_pwquality或pam_cracklib来强制密码复杂度,配合crontab定时任务做批量检查。例如,写一个每周执行的脚本:
#!/bin/bash
EXPIRED_USERS=$(chage -l $(awk -F: '$3 >= 1000 {print $1}' /etc/passwd) 2>/dev/null | awk '/Password expires/ && $NF < 0/{print $1}')
if [ -n "$EXPIRED_USERS" ]; then
echo "以下用户密码已过期: $EXPIRED_USERS" | mail -s "密码过期告警" admin@example.com
fi把这个脚本放进/etc/cron.weekly/目录,每周自动检查并发送告警邮件。这是中小规模环境性价比最高的方案。
八、特殊场景下的轮换策略调整
不是所有账户都适合90天轮换。比如服务账户(运行数据库、Web服务的专用账户),频繁改密码会导致服务中断。对于这类账户,建议设置更长的周期(如180天或365天),但同时必须配合SSH密钥认证、限制登录来源IP、禁用交互式登录等补偿措施。用chage单独设置:
sudo chage -M 365 -m 30 service_account
另外,root账户的密码策略建议单独管理。很多安全基线要求root密码至少180天更换一次,并且root登录应该尽量禁用,改用sudo提权。检查root的shadow条目:
sudo grep root /etc/shadow
九、总结和实操建议清单
把上面的内容浓缩成一份可执行的操作清单:第一,修改/etc/login.defs中PASS_MAX_DAYS为90、PASS_MIN_DAYS为1、PASS_WARN_AGE为7;第二,用chage -M 90 -m 1 -W 7对所有普通用户批量设置;第三,确认shadow文件权限为640且属组为shadow;第四,开启auditd监控shadow访问;第五,确认哈希算法为SHA-512;第六,对服务账户单独设置更长周期并配合其他安全措施;第七,建立定期审计机制,每月检查一次过期账户和shadow权限。做到这七步,你的Ubuntu系统密码管理就达到了行业主流安全水平。
密码轮换不是一个设置完就不管的事情,它是一个持续运营的安全流程。周期设得太短用户反感、设得太长风险累积,90天是目前安全与可用性之间比较好的平衡点。根据你自己的业务场景和合规要求做微调,但底线是:绝对不要使用默认的99999天。
