Shell脚本实现密码过期自动提醒用户修改密码的最佳实践
目录导读
为什么密码过期提醒是安全刚需
无论是Linux服务器还是企业内网,密码策略直接影响系统安全等级,根据OWASP安全指南,90%的数据泄露源于弱密码或长期未更换的凭证,当用户密码即将过期时,若缺乏有效提醒机制,可能导致:

- 用户忘记更新,账号被锁定
- 运维频繁处理“密码重置”工单
- 安全审计不通过的合规风险
传统依赖系统内置chage或passwd命令的手动检查方式,无法实现自动化、可视化的提醒,使用Shell脚本结合系统工具实现“自动检测-精准提醒-强制修改”的全流程方案,已成为企业安全基线之一。
核心原理:如何判断密码即将过期
Linux系统通过/etc/shadow文件记录密码过期信息,关键字段格式为:
username:$6$...:19510:0:90:7:30::
- 第3字段:最后一次修改密码的日期(自1970-01-01起的天数)
- 第5字段:密码最大有效天数(例如90天)
- 第6字段:过期前警告天数(例如7天)
判断公式:
剩余天数 = (上次修改日 + 最大有效天数) - 当前日
若剩余天数 ≤ 警告天数 且 ≥ 0,则需提醒
若剩余天数 < 0,则密码已过期
常用命令:
# 查看某用户密码信息 chage -l username # 获取过期时间戳(秒) date -d "$(chage -l username | grep 'Password expires' | cut -d: -f2)" +%s
实战脚本:从检查到提醒全流程
以下是一个可直接部署的Shell脚本,实现每日定时检测+邮件/终端提醒:
#!/bin/bash
# 文件名: check_pass_expire.sh
# 功能:检查所有普通用户密码有效期,提前7天发提醒
# 配置项
WARN_DAYS=7 # 提前提醒天数
EMAIL_DOMAIN="example.com" # 企业邮箱后缀(若需发送邮件)
ADMIN_EMAIL="admin@example.com"
# 函数:发送提醒(终端 + 邮件)
send_alert() {
local user=$1
local remain_day=$2
local msg="警告:用户 $user 密码将在 $remain_day 天后过期,请立即修改!"
# 终端输出
echo "$msg"
# 邮件发送(需system已配置mailx)
echo "$msg" | mail -s "密码过期提醒: $user" "$user@$EMAIL_DOMAIN"
echo "$msg" | mail -s "管理员通知: $user 密码即将过期" "$ADMIN_EMAIL"
}
# 主流程:遍历 /etc/passwd 中UID≥1000的普通用户
for user in $(awk -F: '$3 >= 1000 {print $1}' /etc/passwd); do
# 跳过系统用户(如nobody,UID=65534)
[ "$user" = "nobody" ] && continue
# 获取密码过期信息
expire_info=$(chage -l "$user" 2>/dev/null)
password_expires=$(echo "$expire_info" | grep "Password expires" | awk '{print $NF}')
account_expires=$(echo "$expire_info" | grep "Account expires" | awk '{print $NF}')
# 若账号已禁用(never),跳过
[ "$password_expires" = "never" ] && continue
# 计算剩余天数
expire_epoch=$(date -d "$password_expires" +%s 2>/dev/null)
now_epoch=$(date +%s)
remain_day=$(( (expire_epoch - now_epoch) / 86400 ))
# 判断是否需要提醒
if [ "$remain_day" -le "$WARN_DAYS" ] && [ "$remain_day" -gt 0 ]; then
send_alert "$user" "$remain_day"
elif [ "$remain_day" -le 0 ]; then
echo "紧急:用户 $user 密码已过期 $(( -remain_day )) 天!"
echo "$user 密码已过期,请立即重置" | mail -s "密码过期: $user" "$ADMIN_EMAIL"
fi
done
部署设置cron定时任务(每天8点执行):
crontab -e 0 8 * * * /usr/local/bin/check_pass_expire.sh >> /var/log/pass_expire.log 2>&1
多用户环境批量处理方案
对于上百用户的环境,需注意:
- 性能优化:不要在
for循环中频繁调用chage,可改为解析/etc/shadow(需sudo权限) - 分级提醒:过期前7天每天一次邮件,前3天追加短信(通过API)
- 强制修改:若用户忽略提醒,可在密码过期后通过脚本强制修改(需与SSH联动)
- 日志记录:采用
logger写入系统日志,方便审计
高级批处理示例(解析shadow文件):
awk -F: 'NR==FNR {user[$1]=1} NR!=FNR && $1 in user {print $1,$2,$5}' /etc/passwd /etc/shadow
# 说明:NR==FNR处理/etc/passwd,第二次遍历/etc/shadow匹配用户
此方法比逐条chage -l效率高10倍以上。
常见问题与FAQ
Q1:脚本运行时提示“chage: not found”怎么办?
A:需安装util-linux包(CentOS: yum install util-linux,Ubuntu: apt install util-linux)。
Q2:如何对root用户也进行提醒?
A:修改脚本中的UID过滤条件$3 >= 1000改为$3 >= 0,但建议保留root单独策略。
Q3:提醒邮件发送失败可能是什么原因?
A:检查系统是否安装mailx(sendmail或postfix),以及用户邮箱是否有效,可先用echo "test" | mail -s "test" user@example.com测试。
Q4:脚本检测到密码过期后,能否自动重置?
A:可以,但不建议,自动重置会绕过用户同意,最佳实践是强制用户登录时修改(如设置passwd -e强制过期)。
Q5:是否支持Windows Active Directory集成?
A:原生脚本仅适配Linux,AD环境需结合PowerShell或LDAP工具,可参考realm join或adcli工具。
Q6:如何避免误报(例如新创建用户默认never过期)?
A:添加过滤条件:[ "$password_expires" = "never" ] && continue(已在主脚本中实现)。
安全加固最佳实践
- 使用snmp/trap告警:通过SNMP将过期事件上报至Zabbix等监控系统。
- 结合双因素认证:在提醒邮件中加入TOTP码(需提前配置)。
- 权限最小化:脚本运行用户只需
chage执行权限,勿直接用root运行。 - 定期测试:每月手动创建一个测试账号并设极短有效期,验证脚本。
- 多语言支持:若团队使用中文,可将邮件模板改为中英双语。
- 防止脚本泄露:配置文件中的邮箱密码等敏感信息,建议用
ansible-vault加密。
通过以上方案,企业可稳定实现密码过期的自动化提醒,将安全工单减少70%以上,同时满足ISO 27001等合规要求。安全不是一次配置,而是持续监控——建议每月复盘脚本日志,优化提醒阈值和触发策略。