☰
John the Ripper密码审计:从哈希加盐到防破解实战
2026/10/1 12:54:39 网站建设 项目流程

John the Ripper,圈子里一般直接叫它 John,是密码审计这件事上绕不开的一个老牌工具。它最早在 1996 年由 Openwall 项目的 Solar Designer 发布,最初只针对 Unix 系统的口令文件,后来演化出社区维护的 jumbo 分支,支持的哈希格式一口气堆到了几百种,从 Linux 的 sha512crypt、Windows 的 NTLM,到各种数据库、压缩包、办公文档的加密结构,基本都能吃。很多人一听到"密码破解"四个字就下意识往灰色地带联想,其实 John 的主战场是防御方:系统管理员用它给自己服务器上的口令做一次强度体检,运维用它审计外包系统残留的弱口令,开发者用它验证自己的加盐和迭代参数够不够硬。它解决的核心问题就一句话——你自以为很安全的密码,到底扛不扛得住字典和规则的轮番冲击。这篇文章适合安全入门的新手、负责系统加固的运维,以及想搞清楚密码存储原理的后端开发者。全程只以本地自建测试环境和自有数据为对象,讲清楚原理、实操和防御思路,不涉及任何越界场景。

1. 为什么密码审计绕不开 John

1.1 密码存储的真相:所谓"破解"其实是在猜哈希

先把一个容易误解的点说透。服务器上从来不保存你的明文密码,它保存的是密码经过某种单向函数运算后的结果,也就是哈希值。这个函数的特点是正向计算很快,反向推算极难——给定一个密码算哈希,眨眼的功夫;给定一个哈希想还原密码,理论上只能靠穷举。所以 John 干的事情,本质上是"猜测 + 验证"的循环:它不断生成候选密码,对每个候选做同样的哈希运算,再和你提供的目标哈希比对,一旦对上了,就说明猜中了。这个过程完全没有"攻破算法"的玄学成分,纯粹是算力和候选质量的比拼。

理解了这一点,很多现象就顺理成章了。为什么同一个密码在不同机器上哈希值长得完全不一样?因为绝大多数现代系统会加盐值(salt)——一段随机数据,和密码拼在一起再算哈希。盐值让"彩虹表"这种预先算好海量哈希的作弊手段失效,因为攻击者得针对每一个盐值重新算一遍,成本瞬间抬高几个数量级。John 处理带盐哈希时,会先解析出盐值,再对每个候选密码套用对应的盐重新计算。这也是为什么 John 的第一步永远是"识别格式",格式认错了,盐值解析错了,后面所有计算都是白费。

还有一个概念是迭代次数(cost / rounds)。像 bcrypt、sha512crypt、PBKDF2 这类专为密码设计的函数,会故意把一次哈希运算重复几千上万次,目的就是拖慢单次验证。对你登录来说,多花几十毫秒无感;对攻击者来说,算力被硬生生稀释成千分之一。John 跑这类哈希时速度会肉眼可见地掉下来,这不是它不行,而是算法设计就是这么要求的。所以我常说,判断一个系统密码存储做得好不好,看它用的什么哈希、迭代多少轮,比看它有没有"加密"这种模糊说法靠谱得多。

1.2 John 的定位:它不是黑客工具,而是密码强度体检仪

在安全圈里,工具本身没有善恶,用法才决定性质。John 被大量渗透测试团队带进授权项目,干的就是"我能不能在两小时内把甲方这批口令猜出来"这一件事。猜得出来,说明口令策略不及格,该改;猜不出来,说明现有策略扛得住常见攻击面。这跟医生拿听诊器听心跳是一个逻辑——工具是诊断用的。

它和另一个常被拿来比较的工具 Hashcat 有什么差别?简单说,Hashcat 更偏重 GPU 上的极限吞吐,追求每秒几十亿次的算力,适合大规模哈希库的批量爆破;John 的优势在于格式覆盖面广、自带规则引擎和多种智能模式、开箱即用,尤其适合针对少量目标做精细化的定向分析。做口令审计时,我通常是先用 John 快速跑一轮字典和单字规则,看看有没有"low-hanging fruit"(低垂的果实),比如用户名变形、常见年份后缀这类;真要上大规模算力,才切到 Hashcat。两者不是替代关系,是分工。

需要把红线划清楚:John 只能用在你拥有或获得明确书面授权的系统上。对别人的系统跑哈希猜测,不管出于什么动机,都是违法的。本文后面所有的演示,都以自己生成的测试哈希为准,你在自己电脑上照做,跑出来的结果也只属于你自己。

1.3 什么场景下该用、什么场景下碰都别碰

适合用 John 的场景我列几个典型的:一是新系统上线前,把默认账号和初始口令拿来测一遍;二是内部安全巡检,抽样检查员工口令里有没有"公司名 + 123456"这类规律;三是数据恢复,自己多年前加密的压缩包忘了密码,用字典碰一碰大概率能想起来;四是后端开发者验证自己选的哈希方案,比如对比 bcrypt cost=10 和 cost=12 在同样字典下的耗时差异。

不该碰的场景同样明确:任何未授权的第三方系统、任何来源不明的哈希库、任何带有真实用户隐私的口令文件。还有一种情况容易被忽略——即便是自己的系统,如果数据涉及他人信息,跑之前也要走内部流程,留存审计记录。工具用得规范,才谈得上专业。

2. John 的破解模式与核心原理拆解

2.1 三种主力模式:字典、单字规则、掩码暴力

John 的核心是几种互补的候选密码生成策略,理解它们各自的脾气,才能用对。

**字典模式(Wordlist)**是最直白的一种。你给它一个密码列表,它逐个拿去做哈希比对。字典的质量直接决定成败。圈内常见的 rockyou.txt 收录了一千四百多万条真实泄露口令,覆盖面很广,但它有个缺点——对中文拼音、行业术语、企业专属词汇基本没辙。我的习惯是准备好几套字典:通用大字典打底,行业术语字典补充,再用目标相关的关键词(组织名、产品名、常见缩写)现场拼一份小字典。定向字典命中率往往比大字典还高。

**单字规则模式(Single crack)**很有意思,它直接拿用户名、GECOS 字段(也就是系统里记录的用户全名、联系方式等信息)作为原材料,套用大量变形规则去猜。比如用户名是zhangsan,它会尝试Zhangsan、zhangsan123、zhangsan2024、zs、nasan这类变形。实测下来,企业内部系统里"用户名 + 简单后缀"的命中率高得吓人,这也是我建议所有系统都禁止口令包含用户名的原因。

**掩码/增量模式(Mask / Incremental)**属于暴力穷举的智能版本。掩码模式允许你用占位符描述密码的"形状",比如?u?l?l?l?l?d?d?d?d表示"一个大写 + 四个小写 + 四个数字",John 只在这个形状空间里穷举,效率比盲目全字符集高得多。增量模式则是 John 内置的马尔可夫链和字符频率模型,它会根据训练数据判断"哪些字符组合更可能出现",把算力优先投给高概率候选。当你知道目标口令大概的长度和构成习惯时,掩码是最省时间的刀。

三种模式不是二选一,实战里是接力跑:先用单字规则秒掉一批弱口令,再用字典扫一遍常见词,最后对剩下的硬骨头用掩码定点爆破。

2.2 哈希格式识别:跑之前先认脸

John 支持的格式有几百种,每种在命令行里都有一个--format=的名字,比如nt(Windows NTLM)、sha512crypt(Linux 现代系统)、raw-md5、bcrypt、zip、rar、office等等。如果格式猜错,你会看到类似"no password hashes loaded"(没加载到哈希)的报错,或者跑半天一个都出不来。

John 本身有自动识别能力,启动时会尝试嗅探哈希的形态。但自动识别不是万能的,尤其对付自定义格式或混合结构时。我的做法是:拿到哈希先肉眼判断一眼,看长度、看前缀、看分隔符结构。$6$ 开头基本是 sha512crypt,$2a$ / $2b$ / $2y$ 开头是 bcrypt,$1$ 是老的 md5crypt,32 位纯十六进制可能是 raw-md5,$NT$ 前缀或裸的 32 位十六进制也可能是 NTLM。拿不准就用john --list=formats列出所有支持的格式,再用john --format=xxx --test对格式做个自检。

2.3 哈希与加盐:为什么"同密码不同值"是好事

再展开说一点原理,因为它直接关系到你该怎么防御。无盐的哈希(比如早期 Unix 的 crypt、裸 MD5)有个致命弱点:相同密码永远得到相同哈希。这意味着攻击者一旦撞出一个,就等于撞出了所有用同一密码的账户,还能直接查彩虹表。加盐之后,每个账户的盐值不同,同样的密码哈希值也完全不同,撞库收益被彻底打散。

更进一步的是"慢哈希"。sha512crypt 默认迭代 5000 轮,bcrypt 通过 cost 参数控制,每加 1 成本翻倍,argon2 还能调节内存占用。这类函数让攻击者的单次尝试成本从微秒级抬到毫秒级。John 跑 bcrypt(cost=12)时,普通 CPU 每秒可能只有几十次尝试,这速度去碰一个 8 位复杂口令,基本是天文数字的时间。所以防破解的第一条铁律从来不是"把密码设长一点"这么简单,而是"用慢哈希 + 每账户独立盐值 + 足够高的成本参数"。

3. 从环境准备到跑出第一个结果的完整实操

3.1 安装:优先用发行版包还是自己编译

在 Debian/Ubuntu 系上,sudo apt install john能装上的是一个相对精简的版本,覆盖常见格式没问题,但 jumbo 分支里的很多高级特性和扩展格式它没有。Kali 等安全发行版自带的就是功能较全的版本。想要完整能力,建议从 Openwall 官网拉 jumbo 源码编译,核心三步:./configure && make -s clean && make -sj4。编译需要 gcc、make、libssl-dev、zlib 等依赖,缺哪个装哪个。编译完成后,可执行文件在run/目录下,像 zip2john、rar2john、ssh2john、office2john 这类辅助脚本也都在那儿。我个人的习惯是把它固定装到一个目录,然后把这个 run 目录加进 PATH,随时调用。

提示:不同发行版打包的 John 版本差异较大,命令行参数和格式名可能对不上。遇到"这个参数明明文档里有却报错"的情况,先john --version看一眼版本,别急着怀疑自己。

3.2 自己造一个测试目标,从零跑通第一轮

正规的练习方式是自己造哈希。Linux 上想模拟一套用户口令文件,可以这样操作:先创建一个测试用户,设置一个你已知的密码,然后把/etc/shadow和/etc/passwd里对应行导出来,用自带的unshadow工具合并成 John 能吃的格式:

sudo unshadow /etc/passwd /etc/shadow > myhash.txt

如果你不想动系统账户,也可以用一个小脚本直接用 openssl 或 python 生成一个带盐的 sha512crypt 哈希,丢进文件里练手。造好目标后,字典模式的基本命令是:

john --wordlist=/usr/share/wordlists/rockyou.txt --format=sha512crypt myhash.txt

跑完想看结果和解出数量,用john --show myhash.txt。这个--show很重要,它把"已解出"和"未解出"分开列出,方便你评估字典覆盖率。

3.3 规则引擎:让字典的命中率翻几倍

光用原版字典,很多密码猜不到;加上规则引擎,命中率会有质的提升。John 内置了--rules参数,会自动套用它的默认规则集,把字典里的每个词做大小写变化、加数字后缀、替换字符(a→@、o→0、e→3)等几十种变形。命令大致是:

john --wordlist=words.txt --rules --format=nt myhash.txt

jumbo 版还支持--rules=Jumbo、--rules=KoreLogic等不同规则集,甚至可以用--rules-stack把多套规则叠加。这里有个经验:规则不是越多越好。规则集越大,单位时间处理的候选越少。粗跑阶段用默认规则快速扫一遍,定向阶段再上重规则,节奏把握好。

3.4 掩码模式:已知密码"形状"时的精准打击

假设你从某个系统的口令策略推断出密码是"首字母大写 + 五个小写 + 两位数字",那掩码模式就是最优解:

john --mask='?u?l?l?l?l?l?d?d' --format=sha512crypt myhash.txt

John 的掩码占位符里,?l小写、?u大写、?d数字、?s符号、?a全字符集。它还有个高级用法叫"混合掩码",可以只对密码的某个位置做穷举,其余位置用已知片段固定,比如你知道密码开头是公司缩写,就可以把那段写死,只爆后面几位。这种"知道一半"的场景,掩码的效率是字典的好几倍。

3.5 压缩包与办公文档:zip2john 系列的用法

热搜里提到的 zip 密码破解,就是 John 这套辅助脚本的典型应用。加密 ZIP、RAR、7z、PDF、Office 文档,John 都不能直接吃,得先用对应的转换脚本把加密结构提取成哈希格式。以 ZIP 为例:

zip2john secret.zip > zip.hash john --wordlist=words.txt zip.hash

zip2john会把 ZIP 里的加密信息抽出来,生成 John 能识别的哈希串。这里提醒一句:传统 ZipCrypto 加密的压缩包,用字典碰出来的速度很快;但如果是 AES-256 加密的 ZIP,John 跑起来会慢很多,因为每次验证都要做一遍密钥派生。这也是一个很好的防御启示——你给别人发加密压缩包时,挑 AES 加密的,安全性远高于老式 ZipCrypto。

4. 提速与资源调度:把跑批的效率榨出来

4.1 硬件选择与算力估算

决定 John 速度的第一因素是硬件,第二是哈希算法本身。粗略地说,针对无盐的快速哈希(如 raw-md5、NTLM),一块中端 GPU 每秒能跑几十亿次;换成 bcrypt 这类慢哈希,同样的卡每秒只剩几千次,差了六个数量级。所以在动手前,值得先花五分钟做一道算术题:目标哈希属于哪一类、你手头的机器每秒能试多少次、候选空间有多大、你能接受跑多久。很多人一上来就挂机开跑,结果发现按当前速度要跑几十年,白白浪费电。

算力估算的实用办法是用--test或先跑一分钟看速率输出。John 运行时会实时显示类似"1234p/s"的速率(p 是 per second,每秒尝试数),拿它乘上你字典的条目数,就知道这一轮大概要多久。心里有数之后再决定要不要换策略,比闷头等强。

4.2 关键命令行参数与调优思路

几个我常用的参数值得说清楚。--fork=N可以多进程并行,把多核 CPU 吃满,在字典模式下收益明显。--node=M/N是把候选空间切成 N 份、当前机器处理第 M 份,适合多台机器分工。--min-length和--max-length限制候选长度,避免在明显不可能的长度区间浪费算力。--session=name给本次任务起个名字,配合--restore就能断点续跑——这个功能对长时间任务太重要了,机器重启或者你手滑 Ctrl+C 之后,用john --restore=name能接着上次的进度跑,不会从头再来。

提示:跑大任务之前务必用--session命名。我吃过不止一次亏,跑了半天的任务因为没存会话,一个中断全部重来。

4.3 断点续跑与结果管理

John 有个很好用的机制:它默认会把进度存在~/.john/john.pot里,这个文件记录所有已解出的"哈希:明文"对。下次对同一批哈希运行时,它会自动跳过已经解出的,只处理剩下的。所以如果你分几轮跑不同字典、不同模式,不用担心重复劳动,John 自己会去重。

管理多个任务时,建议按项目建目录,哈希文件、字典、会话文件分开放,并在文件名里带上日期和模式,比如20240315_nt_rules.session。隔一段时间回头看,你能清楚知道每一轮用了什么策略、解出多少,便于复盘和优化下一轮。这种工程化的习惯,是业余和专业的差距所在。

5. 防破解:把密码强度真正做上去

讲完攻击面,回到这篇文章另一半更有价值的内容——防御。既然我们知道了 John 是怎么工作的,反过来就知道该堵哪些口子。

5.1 从哈希算法层面把地基打牢

如果系统是你自己开发或选型的,密码存储方案是第一道防线。能用 argon2id 就用它,它在抗 GPU 和抗专用硬件方面是目前公认较强的选择;退一步用 bcrypt,cost 参数别低于 10,能上 12 更好(要在登录延迟可接受的前提下);再退一步用 PBKDF2,迭代次数往高了配,几十万轮是常见起点。绝对不要用裸 MD5、裸 SHA1、裸 SHA256 存密码,这些算法快得离谱,等于给攻击者开了绿灯。

还有个容易被忽略的点:salt 必须每个账户独立、足够随机、长度充足(16 字节以上)。见过有系统为了省事用全局固定 salt,那加盐的意义基本没了。另外,加密密钥和哈希存储要分离,别把密钥和密文放在同一个库里,不然被拖库时一锅端。

5.2 口令策略与用户习惯的博弈

强制复杂性(大小写 + 数字 + 符号 + 最小长度)是常规操作,但光靠它容易催生Password1!这种可预测的模式。更有效的组合拳是:设置合理的最小长度(12 位起)、用黑名单挡掉常见弱口令和已泄露口令、禁止口令包含用户名和公司名、定期检查是否有口令出现在泄露库中。NIST 最新的建议其实倾向于"重长度轻复杂度、不强制定期更换",因为频繁换密码反而让用户搞出Spring2024!→Summer2024!这种规律变形。具体怎么权衡,要看你所在环境的风险模型。

用户教育这块也很关键。很多口令之所以被秒破,不是技术问题,是习惯问题——生日、手机号、宠物名、键盘路径(qwerty、1qaz2wsx)占了泄露库的一大块。John 的字典里这些词都在,跑起来就是几秒钟的事。

5.3 系统侧的限速、锁定与多因素

假设密码存储已经做扎实了,还有一层防护要补:限制在线猜测。数据库拖库是离线攻击,password hash 落到攻击者手里,你再怎么限速也没用;但如果攻击者只能在线猜,那限速、失败锁定、验证码、异常登录检测就是有效手段。比如同一 IP 连续失败 5 次锁定 15 分钟、指数退避、异地登录二次验证。

多因素认证(MFA)是终极的兜底。即便口令被猜中,攻击者还缺第二因素(动态口令、硬件密钥、生物特征)。对管理员账户、远程访问入口这类高价值目标,MFA 应该是默认开启而不是可选项。我见过的真实案例里,口令泄露但因为有 MFA 而没造成实质损失的场景,比没有 MFA 而翻车的,多得多。

5.4 把 John 用在防御方:自查清单

防御方怎么用 John?推荐一套自查流程:定期导出自有系统的哈希(在合规前提下),用通用字典 + 规则跑一轮;把所有解出的口令列出来,看看有没有共性问题(比如某个部门普遍用同一套命名规则);把结果脱敏后向上汇报,推动口令策略调整;改完策略过一段时间再跑一轮,对比命中率有没有下降。这个"检测—整改—复测"的闭环,才是安全建设的正确姿势。

注意:自查过程中拿到的明文口令属于高危敏感数据,用完必须立即销毁,任何人都不该留存。这是职业操守,也是合规底线。

6. 常见问题与排查技巧实录

跑 John 的过程中,新手最容易卡在几个固定的地方。我整理成表,方便你对照排查。

现象大概率原因排查与解决
提示 no password hashes loaded格式没认出来,或文件路径/内容有误用--format=手动指定;用--list=formats查支持格式;检查哈希文件是不是被编辑器搞乱了换行
跑了很久一个都没出字典不匹配、算法太慢、候选空间太大先换小字典快速验证流程;确认格式正确;用--test看速率估算总时长
解出的结果看不到忘了用--show跑完执行john --show 哈希文件,或直接查~/.john/john.pot
中途中断要重跑没设置 session加--session=名字,中断后用--restore=名字续跑
压缩包提取哈希报错脚本版本旧或压缩格式特殊更新到 jumbo 版 John,确认 zip2john 等脚本在 PATH 里
Windows 哈希认不出NTLM 和 LM 混淆明确指定--format=nt或--format=lm,二者结构不同

除了表里的,还有几个踩坑经验值得单独说。一是字符编码问题:字典文件如果编码不一致,含中文或特殊字符的候选可能被 John 读错,建议统一用 UTF-8,必要时先用工具去重和清洗。二是字典膨胀的陷阱:有人喜欢把几十份字典无脑合并成一个超大字典,结果跑得慢还不见得命中率高,因为重复条目多、噪声大。正确的做法是先去重、再按命中率和你的目标相关性排序。三是过度迷信暴力穷举:很多人觉得"算力够就能破一切",实际上一个 12 位随机复杂口令的穷举空间大到现代硬件也望尘莫及,真正的攻击者靠的从来是字典和规则,而不是硬刚。所以防御方的重点,恰恰是让用户的口令跳出字典和规则的覆盖范围。

7. 一些个人体会

我从几年前开始把 John 当作日常安全自查的固定环节,最大的感受是:密码安全这件事,技术手段只能解决一半,另一半靠的是流程和习惯。工具再强,如果组织里没有定期审计的机制,没有对弱口令的整改闭环,那每次检查都是走个过场,问题永远存在。反过来,只要每季度老老实实跑一轮、认真整改、下季度复测,口令的整体强度是肉眼可见在提升的。

另一个体会是别把 John 神化,也别把它妖魔化。它就是一把尺子,量的是"你的密码到底有多结实"。真想提升安全性,与其纠结攻击者手里有什么工具,不如把存储算法升级到慢哈希、把 salt 做足随机、把 MFA 铺开、把弱口令黑名单维护起来——这些防御动作的投入产出比,远高于事后发现被破了再补救。至于那个忘了密码的加密压缩包,用字典碰一碰,很多时候确实能想起来当初自己是怎么设的,这算是 John 最无害也最实用的一面了。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询