尧图精选

深入理解/etc/shadow:Linux密码安全与账户策略完全解析

🕒 发布时间:2026/10/1 3:37:36 📁 来源:尧图网络
说实话我第一次认真翻/etc/shadow的时候刚入行没多久当时干了一件蠢事把里面某个账号的哈希值直接贴到群里问这串东西能解密吗。群里安静了足足一分钟然后师傅私聊我你给我等着。后来我才知道这一串看似乱码的字符几乎是 Linux 系统里最不能外泄的东西。今天就把这个影子文件从头到尾掰开揉碎讲清楚包括每个字段的含义、哈希算法的来龙去脉、密码策略怎么设置、以及我在生产环境里踩过的那些坑希望你能少走弯路。这个文件对运维、Linux 学习者、甚至准备面试的朋友都很有用。它平时很低调但账号密码安全、密码策略、账户有效期管理全都靠它。你能通过它判断一个系统里哪些用户是活的、哪些密码已经过期、哪些账号被锁定也能通过它排查密码明明正确却登不进去这类诡异问题。1. 为什么 Linux 会把密码单独放在 shadow 文件里1.1 曾经的 passwd 文件为何不再可靠在讲/etc/shadow之前得先聊聊它的前任/etc/passwd。早年的 Unix 系统确实是把加密后的密码直接存在 passwd 文件的第二个字段里的这个文件保存了所有用户的基础信息而且为了支持普通程序读取用户名和 UID 映射它必须对所有人开放读权限。于是问题就来了任何用户都能看到所有账号的密码哈希值。你可能会想哈希值不是密文吗看到又怎样很多年前大家也是这么想的直到有人把哈希值批量拉下来用字典和暴力工具跑了一晚上弱密码基本全军覆没。密码哈希虽然有不可逆的特点但攻击者并不需要解密他们只需要不断猜测然后把候选密码用相同的算法做哈希比对结果是否一致就行了。整个计算过程完全可以在本地完成不需要碰目标系统也不受登录失败次数限制这种攻击方式叫离线暴力破解效率高得吓人。所以后来系统设计者把密码哈希从 passwd 里剥离出来单独放进一个只有 root 和高权限组才能读取的文件里这就是/etc/shadow中文常叫影子文件。它就像是 passwd 文件的影子只在需要验证身份时被系统读取。这个设计一直沿用至今现代 Linux 发行版默认都是这种双文件结构passwd 负责抛头露面shadow 负责保守秘密。1.2 shadow 文件的权限设计逻辑/etc/shadow的默认权限是-rw-r-----也就是说属主 root 可读写属组 shadow 可读其他用户完全没有权限。这里面的设计有讲究如果只让 root 能读那有些需要验证用户密码的辅助程序因为权限不够只能另想出路于是系统专门建了一个 shadow 组把需要读取密码信息的程序以组成员身份运行而不是直接给它们 root 权限。我见过不少新手为了省事直接chmod 777 /etc/shadow这基本等于把系统的钥匙挂在大门口。普通用户一旦能读 shadow就能把哈希值拿走离线破解弱密码根本撑不住。日常巡检的时候你应该顺手看一眼这个文件的权限有没有被人动过手脚。1.3 passwd 和 shadow 是怎么配合工作的这两兄弟的分工非常明确/etc/passwd里存储用户名、UID、GID、家目录、登录 shell 这些公开信息而真正敏感的密码哈希、密码修改时间、有效期等策略信息全部放在/etc/shadow里。passwd 文件里的密码字段统一用x占位表示真正的密码在 shadow 里。整个认证流程是这样的当用户输入密码登录时系统根据用户名在 passwd 里找到对应的 UID 信息再从 shadow 里取出该用户的密码哈希和密码策略然后对用户输入的密码做相同的哈希计算比对结果是否一致同时还会检查是否有锁定标记、账号是否过期、密码是否过期等状态。这个流程对用户来说是透明的你感觉只是输了个密码就进去了实际上背后通过了层层检查。2. 逐字段拆解 /etc/shadow每一列都别小看2.1 先看一行长什么样下面是一行典型的 shadow 记录myuser:$6$8x3kY9Lz$hJk3mN9pQrStUvWxYzAb2CdEfGhIjKlMnOpQrStUv:18930:5:90:7:30:19220:这一行被冒号分成 9 个字段每个字段都有明确的含义。为了看得更清楚我列成表格字段位置字段名示例值含义1用户名myuser与 /etc/passwd 中对应的登录名2加密密码$6$8x3kY9Lz$hJk...密码哈希值可含锁定标记3最近修改时间18930从 1970-01-01 到上次改密的天数4最短修改天数5两次修改密码之间最少间隔的天数5最长有效天数90密码最多使用多少天后必须修改6警告天数7密码过期前多少天开始提醒7宽限天数30密码过期后还能登录多少天8账号失效时间19220账号在哪一天起彻底不能登录9保留字段空预留目前基本不用2.2 前三个字段用户身份、密码状态和时间起点第一个字段是用户名和 passwd 文件里的是对应关系。你可以用awk -F: {print $1} /etc/shadow快速列出所有有影子记录的用户如果发现某个用户在 passwd 里存在但在 shadow 里找不到说明这个用户可能没有设置密码或者系统配置有异常。第二个字段是密码哈希也是整个文件里最核心的部分。它有些特殊状态值要认清楚。如果值是*说明这个账号的密码处于锁定状态不能用于登录但账号本身不一定是被禁用的如果值以!开头比如!$6$...说明密码被passwd -l或usermod -L锁定过如果值是!!通常表示该用户从未设置过密码或者密码已被管理员清空如果字段完全为空表示该用户没有密码任何人在知道用户名的情况下都能直接登录这在生产环境里是非常危险的状态。第三个字段是密码最后修改时间注意它不是普通的日期格式而是从 1970 年 1 月 1 日到修改当天所经过的天数。比如 18930换算一下大约是 2021 年 10 月末。这个天数的计算方式贯穿整个 shadow 文件的日期类字段后面说的账号失效时间也是同样的算法。如果你需要具体日期一条命令就能搞定date -d 1970-01-01 18930 days我经常用这个命令排查密码改了半天却不生效的问题先确认一下字段 3 有没有被正确更新。2.3 密码策略字段四个数字直接影响账号生命周期从第四个到第七个字段是系统管理员最需要关注的密码策略配置。最低修改天数如果大于 0用户改密时就无法把新密码设得和旧密码一样也不能刚改完马上又改回去。最长有效天数是最常见的配置公司安全规范里90 天改一次密码就是通过这个字段实现的。警告天数是密码快过期时系统会在登录时提示你密码即将过期请尽快修改。宽限天数是密码过期后还能登录多少天如果超过宽限期账号就不能再登录了必须找管理员重置。这四个字段可以由系统级的默认配置来生成初始值它们的来源是/etc/login.defs文件里的PASS_MAX_DAYS、PASS_MIN_DAYS、PASS_WARN_AGE等参数。也就是说新建用户时如果不单独指定系统会按照 login.defs 里的默认值写入 shadow。2.4 最后两个字段账号失效时间和保留位第八个字段是账号失效时间它和密码过期是两回事。密码过期后用户还能通过修改密码来恢复登录但账号一旦过了失效时间这个账号就彻底废了就算密码输对了也进不去只有管理员手动修改这个字段才能恢复。这个字段适合用来管理临时账号比如给外包或实习生开了一个月的权限直接把失效时间设成一个多月后到期账号自动作废省得记着去删。第九个字段是保留字段目前基本都是空的未来的系统版本可能会扩展新功能用它。写脚本处理 shadow 文件时要留意如果这一列是空的按:切割后最后一个空字符串可能让某些编程语言的处理逻辑出问题别到时候找半天 bug 才发现是因为切割后多了个空元素。3. 密码哈希算法$6$ 和 $y$ 背后代表的加密强度3.1 哈希值里的算法标识怎么读再来看密码哈希这个字段常见的格式是$id$salt$hash。id 部分代表哈希算法这是判断系统安全强度的关键。$1$表示 MD5现在基本属于古董级别跑得非常快攻击者用显卡能每秒钟算几十亿次弱密码瞬间就被爆出来。$5$是 SHA-256$6$是 SHA-512这两个是过去十年 Linux 发行版的主流选择但说实话随着硬件性能提升它们也有点不够看了。$y$是 yescrypt是目前较新发行版比如 RHEL 9、Debian 12、Ubuntu 22.04 之后的版本的默认算法计算更复杂、内存开销更大明显提高了暴力破解的成本。另外你也会看到$2a$、$2b$、$2y$这类前缀对应的是 bcrypt 算法一般出现在 BSD 系统或某些刻意配置过的 Linux 系统上。要快速看一下系统里所有用户的哈希算法分布可以写个小命令awk -F: {print $2} /etc/shadow | sed s/\$[0-9a-zA-Z]*$// | sort | uniq -c输出里会显示各种前缀各有多少用户如果发现大量用户还在用$1$或$5$就应该考虑升级策略了。3.2 为什么同样的密码会生成不同的哈希有人可能会疑惑自己在两台机器上设置相同密码shadow 文件里的哈希值为什么完全不一样。答案是盐值 salt。每次设置密码时系统都会生成一段随机字符串作为盐放在$符号分隔的第二个位置。加盐的作用有两点一是让相同的密码产生不同的哈希结果攻击者无法用一张彩虹表批量匹配所有用户二是盐本身参与哈希计算大大增加了预计算的成本。从这个角度也能理解为什么解密哈希这种事基本不现实——你没法从哈希反推出密码只能逐个猜测碰撞。但有了盐之后攻击者甚至连一次算好批量对撞的偷懒方案都用不了只能老老实实对每个用户的哈希单独爆破。3.3 如何生成指定算法的密码哈希有时候我们需要手动构造一个明文密码对应的 shadow 哈希用于批量创建用户或者恢复某个被误修改的条目。常用的办法有以下几种。用 openssl 生成 SHA-512 密码openssl passwd -6命令会让你输入两次密码然后输出$6$...格式的完整哈希直接粘贴到 shadow 里就能用。用 mkpasswd 生成指定算法的密码这个方法需要安装 whois 包mkpasswd -m sha-512 MyPssw0rd虽然叫 whois 包但里面的 mkpasswd 工具确实能干这个活。用 Python 也可以生成python3 -c import crypt; print(crypt.crypt(MyPssw0rd, crypt.mksalt(crypt.METHOD_SHA512)))需要注意不管用哪种方式命令执行过后都会在 shell 历史里留下痕迹生产环境下用这种方法建议加上history -d清理或者干脆用read -s结合管道传参。我见过有人直接在命令行里写密码生成哈希结果哈希和明文密码一起留在.bash_history里等于白忙活一场。3.4 哈希算法升级这件事该如何落地如果你所在环境的系统版本比较老shadow 文件里还是$6$甚至$1$的哈希我建议在条件允许的情况下升级到 yescrypt。具体怎么做呢最粗暴的办法是给用户重置密码让系统用新的默认算法重新生成哈希但这样要通知所有人改密码在存量系统上操作成本很高。另一种思路是在环境允许的情况下逐步迁移先把/etc/login.defs或 PAM 配置里的默认算法改成 yescrypt然后配合密码过期策略让用户下次登录时强制改密新密码就会以 yescrypt 形式写入 shadow。这个过程虽然慢但用户无感安全收益是实打实的。需要注意如果系统里还跑着老版本的 NIS 客户端或某些兼容性很差的程序它们可能不认识$y$前缀升级前要做好兼容性测试。4. 密码策略实战不靠猜用 chage 精确管理账户生命周期4.1 chage 命令到底能查看和设置什么chage 的全称是 change age专门用来查看和修改 shadow 文件里的密码时效信息。用chage -l 用户名可以查看某个用户的密码过期信息输出包括上次改密时间、密码过期时间、账号失效时间等全是人类可读的日期格式不用自己手动去换算天数。这对于快速了解一个账号的状态非常方便。常用参数归纳一下参数作用示例-l查看密码时效信息chage -l zhangsan-d设置最近改密日期0 表示下次登录强制改密chage -d 0 zhangsan-m设置最短修改天数chage -m 7 zhangsan-M设置最长有效天数chage -M 90 zhangsan-W设置过期前警告天数chage -W 7 zhangsan-I设置过期后宽限天数chage -I 30 zhangsan-E设置账号失效日期chage -E 2025-12-31 zhangsan用过一段 chage 之后你会发现它本质就是一个更友好的 shadow 文件编辑器所有修改最终都会落回/etc/shadow对应的字段。4.2 让新用户首次登录必须改密码公司里给新员工开账号的经典场景是管理员设置一个初始密码要求用户第一次登录时必须改成自己的密码。实现方法很简单创建用户后用一条命令把最近修改日期设为 0useradd -m zhangsan echo Init12345 | passwd --stdin zhangsan chage -d 0 zhangsan这样用户第一次登录时系统会强制要求修改密码新密码才会正式生效。这个0会直接写入 shadow 的第三个字段显示为 0代表密码已过期必须修改。顺便提醒一句passwd --stdin这种方式虽然方便脚本化但明文密码会经过管道传给 passwd要注意脚本文件的权限和日志记录避免密码泄露。4.3 批量设置密码策略的实操方案当系统里有大量用户需要统一实施密码策略时挨个敲chage是不现实的。我一般会结合/etc/login.defs和批量脚本来做。先把系统默认参数修改好这样后续新建的用户自动就带上策略。然后对存量用户可以用一行循环批量设置for user in $(awk -F: $3 1000 $3 65534 {print $1} /etc/passwd); do chage -M 90 -W 7 -I 30 $user done这段命令的逻辑是找出所有 UID 在 1000 到 65534 之间的普通用户然后逐个设置 90 天最长有效、7 天警告、30 天宽限。执行完之后抽几个用户用chage -l复查一遍确认策略写入了 shadow 文件。4.4 临时账号自动失效的正确姿势对外部合作方开临时账号时最怕的不是忘记给权限而是忘记回收权限。与其在日历上设提醒不如直接用账号失效时间兜底。给合作方账号设一个明确的失效日期chage -E 2025-08-31 wangwu这个日期会写入 shadow 的第八个字段。到了 2025 年 8 月 31 日那天账号自动作废不管密码对不对都无法登录。如果合作延期用chage -E再往后调就行。这个功能对审计和合规很有帮助每次检查时直接看 shadow 文件就能确认哪些账号是临时的。5. 手把手实操改密码、锁账号、手动编辑 shadow 文件5.1 锁定和解锁账号背后的 shadow 变化有时候我们要临时禁止某个账号登录但又不想删除用户最常用的办法是锁定密码。执行passwd -l 用户名或usermod -L 用户名之后shadow 里该用户的密码哈希前面会多出一个!前缀变成类似!$6$...的样子。这个感叹号让哈希值永不可能匹配成功所以用户无论输什么密码都登录不了。解锁对应的命令是passwd -u 用户名或usermod -U 用户名操作后!前缀会被移除原来的哈希值恢复可用。这里有个坑要提醒如果用户本来就没有设置密码shadow 里是!!此时执行passwd -u不一定能解锁成功因为系统分不清这个账号到底是从未设过密码还是被锁定后清空了密码。遇到这种情况直接重新设置一个新密码是最稳妥的。5.2 为什么推荐用 vipw -s 而不是直接 vi有时需要手动修改 shadow 文件里的某个字段比如调整一个用户的失效日期或者修复被误改的哈希值。虽然用vi /etc/shadow也能改但我强烈建议用vipw -s命令。它本质上还是调用编辑器来修改 shadow 文件但会额外做几件事一是检测文件是否被其他进程占用避免并发写入导致的数据损坏二是在编辑完成后自动触发相关的校验和同步降低因语法错误导致所有用户无法登录的风险。同样修改 passwd 文件时推荐用vipw而不是直接vi /etc/passwd。改完以后还可以运行pwck来校验 passwd 和 shadow 的一致性它会检查用户名、UID、家目录等信息的对应关系指出可能存在的问题。5.3 手动编辑 shadow 必须记住的三条铁律手动编辑这个文件有一系列不容忽视的注意事项。第一开始编辑前务必备份原文件可以简单执行cp /etc/shadow /etc/shadow.bak出错时立刻恢复。第二所有日期字段都必须换算成从 1970-01-01 开始的天数直接填一个普通日期进去是不生效的可能还会让字段解析异常。第三编辑完成后建议用cat /etc/shadow检查一下每行冒号数量是否还是 9 个字段多一个冒号或少一个冒号都有可能让系统读取出问题。如果你发现某个用户的哈希值被误改导致无法登录不用慌可以进入单用户模式或救援模式重新设置密码或者从备份里恢复该行。5.4 用 pwunconv / pwconv 理解数据流转这里顺带提两个可能会在面试里遇到、平时又用得比较少的命令pwconv和pwunconv。pwconv 的作用是把 passwd 文件里的密码信息同步到 shadow它会在 passwd 里没有对应的 shadow 记录时自动创建。pwunconv 则相反它把 shadow 里的密码信息合并回 passwd 文件然后删除 shadow 文件让系统回到早期那种密码全在 passwd的状态。听起来 pwunconv 似乎很复古而且还方便少一个文件但在现代 Linux 系统上几乎不应该使用它。一旦执行密码哈希重新对所有人可读还把系统的默认安全设计给推翻了。我有一次在实验环境里手滑执行过还好只是一台测试机立刻用pwconv恢复了。你说这个命令存在的意义是什么更多是历史兼容和特殊故障恢复日常运维请把它当核弹按钮供起来。6. 常见问题与排查技巧实录6.1 密码明明正确却登录不上这个问题的出现频率极高。第一反应就是检查用户名对应的 shadow 记录是否存在异常。我排查的顺序一般是这样的先看哈希值前面有没有!前缀有的话就是被锁定了再看第三字段是不是 0是 0 就会被强制要求改密码某些终端界面可能没给用户改密的机会表现成登录失败然后看最后修改时间加上最长有效天数和宽限天数之后是否已经过了当前时间这就相当于密码已经过期且超过宽限期。如果这些都正常还得检查/etc/shadow的权限是不是被改成了普通用户可读。这不是危言耸听有些系统初始化脚本或者安全扫描工具可能会误调整文件权限普通用户一旦可读某些安全性要求高的 PAM 模块甚至会拒绝读取或被第三方安全软件标记。用ls -l /etc/shadow看一眼标准状态是-rw-r-----并且属主 root、属组 shadow。6.2 忘记 root 密码如何进入系统重置这个场景是每个运维的必修课。重启系统在 GRUB 引导菜单选中内核按 e 进入编辑模式找到以linux开头的那一行在末尾加上rd.break或者init/bin/bash然后按引导进入紧急模式。不同系统的具体操作略有差异网上也很容易搜到对应发行版的详细步骤这里重点说几个容易踩坑的地方由于 systemd 时代根文件系统默认可能是只读挂载你需要先重新挂载mount -o remount,rw /然后才能执行passwd root修改密码。修改完成后如果之前设置了 SELinux还要考虑重置文件安全上下文否则可能引发连锁问题。在虚拟化环境里进行操作比物理机方便很多你可以在虚拟机控制台直接操作不用跑到机房。6.3 shadow 文件被误改后大规模登录失败我踩过最狠的一次坑是写脚本批量改密码时逻辑写错给一大批用户写入了错误的哈希值那一堆账号全部无法登录。当时最要命的是 root 密码也被脚本覆盖了差点就得去机房处理。事后总结的经验有两条。一是所有批量操作脚本里必须加入校验环节比如操作前备份、操作后抽样验证、脚本里加保险机制只处理指定前缀的用户。二是遇到大规模故障时不要慌如果系统还能进入单用户模式或者有带外管理卡可以先从最近备份恢复/etc/shadow如果不能恢复就逐一用passwd给关键账号重新设置密码。这个教训让我形成了每周自动备份 /etc 下敏感文件的习惯建议你也提前把备份方案做好。6.4 常用排查命令速查把日常和 shadow 相关的排查命令整理成一个速查表方便直接复制使用需求命令查看所有用户哈希算法分布awk -F: {print $2} /etc/shadow 配合前缀统计查看某个用户的完整密码策略chage -l 用户名查看某个用户是否被锁定passwd -S 用户名校验 passwd 和 shadow 一致性pwck检查 shadow 文件权限ls -l /etc/shadow手动安全编辑 shadow 文件vipw -s备份 shadow 文件cp /etc/shadow /etc/shadow.日期6.5 安全基线检查与几个容易被忽视的点最后说点安全加固的实操心得。第一定期检查 shadow 文件里是否存在空白密码字段也就是密码字段为空的用户一旦发现立刻补上密码或锁定账号。第二检查是否有多个用户共享同一个 UID 但 shadow 中密码不一致避免权限判断混乱。第三备份系统时如果包含/etc目录注意备份文件本身的权限和存放位置shadow 文件如果不小心被打包上传到了对象存储或无访问控制的备份里等于把密码哈希开源了。第四有条件的话可以结合日志审计软件对/etc/shadow的文件变更做监控一旦有非 root 进程尝试读取立刻告警。根据我个人经验搞定/etc/shadow的核心不在于把 9 个字段背得多熟而在于理解这个文件在认证链路中扮演的角色。很多看似诡异的登录问题根源都在 shadow 文件的某个字段或权限上。你现在再回头看那些密码无法修改账号到了时间自动消失哈希算法太老想升级之类的需求应该能顺着字段一层层找到答案。最后再分享一个排查小技巧下次你遇到跟密码有关的疑难杂症第一步永远先备份/etc/shadow然后逐字段做减法排查比瞎猜快得多——这是我在无数次踩坑之后总结出的最短路径。
上一篇/下一篇内容由系统自动关联 返回资讯列表 →