1. 修改密码前的底层认知与整体思路
1.1 密码到底存在哪里,验证链路是怎样的
很多刚接触Linux运维的朋友,第一次接到“修改root密码”这个任务时,脑子里冒出来的想法是:登录进去执行passwd,输入两遍新密码,完事。确实,这是最常见的路径,但如果你想在真实环境里不出岔子——尤其是面对生产服务器、客户系统、云主机时——还是得先把底层的密码存储和验证机制搞清楚。
Linux系统的账号密码信息主要存放在两个文件里:/etc/passwd和/etc/shadow。/etc/passwd是全局可读的,里面保存了用户名、UID、GID、家目录、登录Shell等信息。密码哈希字段在现代系统上不会放在/etc/passwd里,而是放在只有root用户或特定权限组才能读取的/etc/shadow文件中。这也是为什么普通用户能查询自己的账号信息,却不能随便看到其他人的密码哈希。
/etc/shadow里每一行大致是这样:
root:$6$saltsalt$hashhashhash:19000:0:99999:7:::字段用冒号分隔,依次是:用户名、密码哈希、最后一次修改密码的日期、最短修改间隔、最长有效期、警告天数、宽限天数、失效日期和保留字段。密码哈希前面的$6$表示SHA-512算法,$y$是yescrypt,$2b$是bcrypt,不同发行版默认算法不一样。CentOS 7 时代常见$6$,较新版本系统则开始转向$y$。了解这些算法的意义在于:当你用passwd命令修改密码时,系统会根据/etc/login.defs和 PAM 配置选择对应的哈希算法,这个选择通常不需要你手动干预,但如果你在写脚本调用某些底层的库函数,就必须注意算法兼容性。
验证链路也不复杂:用户登录时输入密码,系统根据用户名读取/etc/shadow中对应记录的哈希,用相同的salt对输入的密码做哈希,再将结果与存储的哈希比对,一致即通过。整个过程由 PAM(可插拔认证模块)统一调度,passwd只是前端工具,真正做事的是pam_unix.so这类模块。理解这一点,你才能在遇到“明明密码改成功了,SSH却登录不了”这种诡异问题时,想到去检查 PAM 配置而不是傻乎乎地再改一遍。
1.2 密码安全策略决定了你的修改方式
修改密码不是瞎改,安全策略才是背后真正的主导逻辑。常见的策略要求包括:密码最小长度、复杂度(包含大写、小写、数字、特殊字符)、定期更换周期、防止使用最近使用过的密码历史。这些策略在/etc/login.defs和/etc/security/pwquality.conf里定义。运维人员在执行密码修改时,需要提前确认系统当前启用的密码复杂度规则,否则可能遇到passwd提示BAD PASSWORD: it is too simplistic/systematic之类的报错。
举例来说,/etc/security/pwquality.conf中常见参数有:
minlen = 8 dcredit = -1 ucredit = -1 lcredit = -1 ocredit = -1minlen是最小长度,dcredit表示至少包含多少个数字(负值表示至少要有几个),ucredit是大写字母数量,lcredit是小写字母数量,ocredit是特殊字符数量。如果这些参数被设置得比较严格,你试图设置一个简单的短密码就会遭到拒绝。这其实是系统在保护你,而不是在为难你。
从运维视角看,修改密码前应该理清楚三个问题:这次修改是主动的安全加固,还是因为密码泄露的应急响应,或者是账号权限交接?如果是应急响应,改完密码之后还要检查是否有异常登录记录、是否有恶意计划任务残留;如果是权限交接,除了改密码,还应该考虑把密钥对、双因子认证信息一并更换。密码本身只是账号安全的一部分,不该孤立处理。
2. 修改root密码:从命令行到救援模式的完整路径
2.1 三种场景下的root密码修改
第一种场景最简单:你已经以root身份登录系统,或者有一个拥有sudo权限的普通账户。此时修改root密码只需一条命令:
sudo passwd root执行后系统会提示输入新的root密码并确认。注意这里有个细节:如果当前用户本身就是root,passwd root可以直接执行;如果是普通用户使用了sudo,则需要输入当前用户的密码来获得提权能力。很多人对sudo passwd root和sudo passwd两个命令搞混,前者修改的是root用户的密码,后者在默认配置下修改的是当前普通用户自己的密码。后者通常用于普通用户主动修改自己的密码,但前提是用户自己知道当前密码。
第二种场景:只记得普通用户密码,不记得root密码,但普通用户有sudo权限。这种情况不需要重启系统,也不需要进救援模式,直接sudo passwd root即可。这提醒我们一个安全要点:拥有sudo权限的普通用户,实质上就是能改root密码的准管理员。日常运维中不要把sudo权限随便授予不信任的账号。
第三种场景:连普通用户密码都不记得,或者系统只允许root登录但root密码丢失。这种情况必须走救援流程,我会在第4章详细展开。这里先给出一个高层面结论:只要能接触到物理机或管理控制台,Linux系统的root密码就总有办法重置,区别只是麻烦程度。
2.2 root账号的锁定与解锁
除了修改密码,root账号还有一个容易被忽略的操作维度:锁定与解锁。所谓“锁定”,本质上是通过特殊的方式让密码验证永远无法通过,常见做法有两种:一种是把密码哈希字段设置成不可用的值(比如!或*),另一种是通过passwd -l命令设置账号锁定状态。对应的解锁命令是passwd -u。
查看一个账号当前的状态可以用:
passwd -S root输出中会显示root L或root P之类的状态,L表示锁定,P表示可用密码。在新装的Ubuntu系统上,root账号默认是锁定状态,管理员通过sudo passwd root设置密码时,系统会自动解锁。在CentOS/RHEL系统上,root默认是可登录的,除非安装时显式配置了禁止root SSH登录。
这里我给出一个实用建议:如果你的服务器暴露在公网上,root账号的密码哪怕设置得很复杂,也不建议允许root直接通过SSH登录。常规做法是创建一个普通用户并授予sudo权限,把SSH的PermitRootLogin设置为no。原因很简单:root账号是暴力破解的首要目标,禁掉直接登录能大幅减少攻击面。但要注意,如果关闭了root SSH登录,同时又把唯一有sudo权限的普通用户的密码忘了,后果就是你得通过物理控制台走救援流程,云服务器就得用网页端的VNC登录,折腾不少,所以改配置前要有兜底方案。
3. 修改普通用户密码:从单人到批量
3.1 单用户密码修改的正确姿势
普通用户修改自己的密码,命令很简单:
passwd系统会先让你输入当前密码,验证通过后才允许设置新密码。整个过程不需要root权限,但这里的限制是:你只能修改自己的密码,而且必须先通过旧密码验证。这是Linux系统的一种自我保护机制——即使有人短暂占用了你的终端,也无法在没有旧密码的情况下轻易改变你的密码。
如果你是管理员,需要重置某个普通用户的密码,则需要root权限:
sudo passwd zhangsan执行后系统不会询问旧密码,直接设置新密码。这在实际运维中很常见,比如员工忘记密码、账号需要临时接管、入职离职交接等。管理员重置密码时,不需要知道用户当前的旧密码,这也符合安全原则:管理员不需要知道用户的旧密码,只需要能创建新的凭据。
需要注意一个常见误区:用sudo passwd zhangsan修改密码后,如果该用户当前已登录系统,他的现有SSH会话不会被踢出,已经建立的密钥登录也不受影响。这意味着,如果账号被盗且攻击者已经建立了会话,单纯的密码重置并不能立刻切断攻击者。此时还需要配合pkill -u zhangsan切断用户进程,甚至进一步检查攻击者是否植入了后门。安全应急时,改密码只是第一步,不是全部。
3.2 批量修改与首次登录强制改密
服务器数量一旦变多,单条passwd命令就忙不过来了。常见需求是把一批用户密码批量设置为某个统一值,或者根据用户列表逐一设置。这时可以用chpasswd命令。
Debian/Ubuntu系的标准做法是通过管道给chpasswd输入数据:
echo "zhangsan:NewPass123!" | sudo chpasswd这种方式的好处是支持批量处理,可以把多行用户名和密码一次性喂进去:
sudo chpasswd < users.txtusers.txt每行格式为用户名:新密码。在RHEL/CentOS系上,有人习惯用echo "NewPass123!" | passwd --stdin zhangsan,--stdin表示从标准输入读取密码。这个选项在Debian系的passwd上不支持,所以跨发行版时我更推荐chpasswd,它的兼容性更好。写脚本时还要注意:用命令行直接传密码,会把密码暴露在shell历史和进程列表中,稳妥的做法是通过read -s从终端交互式读取,或把密码文件权限限制为600并在用完立即删除。
批量修改之外,还有一个高频需求:首次登录强制改密。管理员为用户分配初始密码后,希望用户第一次登录时必须先修改为自己的秘密。实现方法是在设置初始密码之后,把密码的最后修改日期归零:
sudo chage -d 0 zhangsan这样用户下次登录系统时会被强制要求修改密码,修改完成后才能正常使用环境。这里的原理是chage -d 0把lastchg字段设置为0,而系统的时间从1970年1月1日算起,因此系统认为密码已经过期,触发改密流程。这个命令不会影响密码本身的哈希值,只是修改了有效期元数据。
4. 忘记密码后的救援流程
4.1 systemd发行版下的救援模式处理
无论什么场景,救援模式的基本思想是一致的:在操作系统完整启动之前,通过内核参数或启动菜单进入一个特权环境,重新挂载根文件系统为可写状态,然后直接修改/etc/shadow或执行passwd命令。整个过程依赖物理控制台或云平台的远程控制台,依赖SSH是行不通的,因为SSH服务此时还没起来。
以常见的systemd发行版(CentOS 7及以上、Ubuntu 15.04及以上、Debian 8及以上)为例,标准操作流程是:
- 重启服务器,在GRUB菜单出现时,选中默认内核启动项,按
e键进入编辑模式。 - 找到以
linux或linux16开头的那一行,在行尾添加一个临时内核参数。CentOS系通常用rd.break,Ubuntu/Debian常用systemd.unit=rescue.target,也有的系统直接写init=/bin/bash。 - 按
Ctrl+X或F10启动系统,进入带root权限的紧急环境。 - 此时根文件系统往往是只读挂载的。需要手动重新挂载为读写模式,才能修改密码文件。
下面是CentOS系rd.break的完整处理命令序列:
mount -o remount,rw /sysroot chroot /sysroot passwd root touch /.autorelabel exit exit这里的细节容易踩坑。rd.break模式下,真实根文件系统会被挂载到/sysroot,而当前的环境是一个精简的初始内存盘环境。如果不做chroot /sysroot就执行passwd root,修改的是救援环境的密码,与真正系统无关。touch /.autorelabel是为了在SELinux强制模式下触发文件标签重建,如果不做这一步,改完密码之后系统可能因为SELinux上下文异常而无法正常登录。这一步很多人会漏掉,导致绕了一大圈发现密码还是不对。
Ubuntu/Debian系使用systemd.unit=rescue.target进入救援模式后,系统通常会在一个较完整的环境里提示输入root密码或允许直接提权。如果提示需要root密码但你恰好忘了,可能需要改用init=/bin/bash这种方式,流程类似:
mount -o remount,rw / passwd root exec /sbin/init4.2 重置后的权限与安全注意事项
救援模式下重置密码是最后手段,但这里有几个必须注意的地方。
第一,整个救援过程绕过了正常的认证机制。任何能够物理接触服务器的人都可以通过这种方式重置root密码,所以物理安全和控制台访问权限的重要性不亚于系统密码本身。在数据中心托管服务器时,机柜的物理访问控制必须管好。
第二,重置密码后会遗留一些痕迹和风险。比如,GRUB配置如果被临时改动过(虽然大部分场景是临时启动参数),要检查是否有异常残留;SELinux的relabel操作会触发重启后的自动标记过程,这个过程在大型文件系统上可能耗时较长,千万别以为机器卡死了。
第三,救援模式重置的是root密码,但在现代云服务器环境中,很多用户是用普通账号加sudo的方式来管理的。如果这次故障是由普通用户密码遗忘引起的,恢复root密码后,还需要把普通用户密码一并重置,或者直接创建新的管理用户。我经常见到有人重置了root密码后就以为万事大吉,结果应用服务还是起不来,因为应用配置里用的是另一个服务账号,密码同样到期了。
5. 密码策略、权限陷阱与防坑指南
5.1 密码强度与有效期配置
密码修改本身不难,难的是合理的密码策略。作为一个长期实践者,我认为一个合格的服务器密码策略至少要覆盖四个维度:长度、复杂度、有效期、历史次数。
长度和复杂度在/etc/security/pwquality.conf中配置,我已经在前面提到了minlen、dcredit等参数。实际操作中,管理员在做完密码策略调整后,需要立刻测试效果。测试方式就是尝试执行passwd设置一个不符合策略的密码,观察是否会被拦截。有些管理员改完配置后不验证,结果部署上线时才被反馈说“密码怎么都改不了”,很被动。
有效期配置通过chage命令完成。查看用户密码过期信息:
sudo chage -l zhangsan设置90天有效期、提前7天警告:
sudo chage -M 90 -W 7 zhangsan-M指定最大有效期天数,-W指定过期前警告天数。还可以设置账号的失效日期-E,这个参数在做临时账号时特别好用。比如给外包团队开一个从今天起存活30天的账号,就可以chage -E 2026-06-30 zhangsan,到期后账号自动失效,无需手动删除。
密码历史是另一个容易被忽略的环节。/etc/pam.d/system-auth(RHEL系)或/etc/pam.d/common-password(Debian系)中可以配置remember=N参数,让PAM记住最近N次使用的密码,防止用户反复使用同一个密码。注意,这个参数不是万能的,它只在通过PAM的密码修改流程中生效,直接改/etc/shadow绕过PAM的历史记录约束是可以的,但这种操作本来就属于特殊管理场景。
5.2 权限层级中最容易踩的三个坑
第一个坑是sudo权限的配置不当。很多人在/etc/sudoers里给普通用户配置了类似zhangsan ALL=(ALL) ALL的规则,本意是让特定用户可以使用sudo执行管理命令。但这条规则同样允许该用户执行sudo passwd root,相当于间接获得了root权限。我建议,如果你只想让用户能管理某一个服务,就把sudo规则细化到具体命令,比如:
zhangsan ALL=(root) /usr/bin/systemctl restart myapp这样该用户只能执行这一个命令,权限收敛了很多。不要嫌配置麻烦,权限整改的成本永远比安全事件后的复盘成本低得多。
第二个坑是误用passwd命令导致锁死自己。典型场景是:管理员在/etc/passwd或/etc/shadow中手工编辑文件时出现了语法错误,比如字段数量不对、密码哈希里混入了非法字符,会导致所有用户无法登录。处理这类问题时,务必在改动前对/etc/shadow做备份,并确认备份文件权限是600。还有一种是自己把root密码设置为空或错误地执行了passwd -l,然后重启后发现再也无法登录。所以我养成了一个习惯:在修改root密码后,不立即重启服务器,而是先开一个新的SSH会话验证新密码可以登录,再继续后续操作。这条建议特别重要,尤其是在远程维护服务器时,一旦旧会话断掉而新密码又验证不过,你就把自己锁在门外了。
第三个坑是混淆了密码锁定和账户过期的区别。passwd -l锁定的账号,其密码验证会失败,但密钥登录、服务账号运行等通常不受影响;usermod -L和passwd -l在历史语义上略有差异,有些发行版简化了实现。而chage -E设置的账户失效日期,作用是在指定日期之后该账号无法再登录系统。这两种机制的目的不同,不要混用。比如你想临时停用一个员工账号,正确做法是锁定密码并检查其进程,而不是只设置很短的失效日期。
6. 高频问题排查与实操经验
6.1 典型报错与解决方案对照
密码操作中遇到的报错,大多数集中在以下几种,我整理了一个速查对照表:
| 报错或现象 | 根本原因 | 解决方案 |
|---|---|---|
passwd: Permission denied | 当前用户权限不足 | 使用root或sudo执行passwd 用户名 |
passwd: Authentication token manipulation error | /etc/shadow权限异常或只读挂载 | 检查shadow权限是否为-rw-------,确认文件系统非只读 |
BAD PASSWORD: it is too simplistic/systematic | 新密码不符合复杂度策略 | 更换更复杂的密码,或临时调整/etc/security/pwquality.conf |
su: Authentication failure | root密码与当前用户密码混淆 | 确认使用的账号是否正确,尝试sudo passwd root重新设置 |
chage: user 'xxx' does not exist | 用户名拼写错误或用户不存在 | 先用id 用户名确认账号存在 |
| 修改密码成功但SSH登录失败 | SSH配置禁用了密码认证,或PAM配置异常 | 检查/etc/ssh/sshd_config的PasswordAuthentication和 PAM配置 |
其中Authentication token manipulation error是最让人头疼的一个。常见的原因是/etc/shadow文件被设置成了不可修改状态,比如管理员执行过chattr +i /etc/shadow。解决方法是先用lsattr /etc/shadow查看属性,如果带i标志,需要用chattr -i /etc/shadow解除锁定后再修改密码。这个陷阱往往不是配置错误,而是防御性操作带来的副作用,排查时要有这个意识。
6.2 一些能让你少走弯路的经验
最后分享几条我在实际运维中沉淀下来的经验,不是文档里能查到的,但对生产环境非常有价值。
第一,改密码前先检查当前会话的身份确认方式是否可靠。我见过不止一次,管理员在终端里执行了sudo passwd root,结果因为键盘布局不同,新旧密码里的特殊字符输错了,然后所有凭据全部失效。稳妥的做法是:修改前先验证一次当前密码是否有效,修改后再立刻用另一个终端验证新密码能正常登录,全程不要断开旧会话。这条“先开逃生窗口”的规则,比任何密码策略参数都更重要。
第二,自动化的密码轮换脚本里,务必包含错误处理。用chpasswd批量改密码时,如果某个用户名不存在,整个脚本默认可能继续执行而不报错。我建议脚本中逐行读取用户列表,每一行执行后解析返回值,遇到非零退出码就记录下来,最后统一汇总。不要依赖终端上飘过的警告信息,生产环境里没人会实时盯着输出看。
第三,注意涉密场景的文件清理。passwd命令交互输入密码时不会留下历史记录,但管道方式传入密码时,bash的历史文件里可能记录下完整的命令内容。如果你使用了echo "user:pass" | chpasswd,检查一下~/.bash_history,如果记录了明文密码,记得清理。更安全的替代方案是用read -s读取密码到变量,再通过管道传给chpasswd,或者干脆用密码文件加标准输入的方式,但用后立刻删除文件并shred覆盖。
第四,在云服务器和虚拟化平台环境中,密码修改完毕后,建议做一次快照或镜像备份。原因很现实:救援模式下的步骤如果出现意外——比如GRUB配置被误改、内核参数残留——恢复原始状态的成本远大于快照的成本。我通常在重置root密码或者大规模调整用户策略之前,都会先拍一个快照,这在操作失误时能直接回滚,是非常高效的兜底手段。
修改密码这件事,看起来简单,背后的机制、策略和风险其实不少。如果你正在维护一台Linux服务器,我建议你从现在开始就建立一套完整的账号管理清单:root密码多久轮换一次,哪些普通用户拥有sudo权限,密码策略参数是否已经成文规范,/etc/shadow的备份无法恢复时的应急预案是否明确。把这些理清了,密码修改就从“临时救火”变成了日常运维中一件闭环、顺手的小事。