首页 › programming › 哈希不是加密:一行代码毁掉一亿密码

哈希不是加密:一行代码毁掉一亿密码

导语:开发者最常犯的"安全幻觉"

如果你问一百个程序员"密码该怎么存",至少会有十几个人脱口而出:"加密存呗。"——然后把用户的密码丢进 MD5 或 SHA-256,往数据库里一塞,就觉得自己做完了安全。

这正是 Computerphile 这支经典短片《Hashing Algorithms and Security》想要击碎的幻觉。它只用十几分钟,就把一个被无数团队踩烂的坑讲透了:哈希不是加密,存了哈希不等于存了密码,而"加密"密码本身就是一种危险的设计。视频里,诺丁汉大学的 Robert Miles 博士没有堆砌术语,而是用一份文档、一处改动、一串面目全非的指纹,向你演示哈希函数最反直觉的力量。

这支视频值得反复看,不是因为它有多新,而是因为它回答了一个看似简单、实则每年都在制造上亿账号泄露的根本问题:当你必须验证一个密码、却又绝不能知道它是什么时,你到底该怎么做?看完这篇拆解,你会理解为什么 hash(password) 是新手代码,为什么加盐只是第一步,以及为什么 bcrypt、argon2 这类"故意设计得很慢"的算法,才是密码存储的真正答案。

视频背景卡片

项目 内容
视频标题 Hashing Algorithms and Security
频道 Computerphile(诺丁汉大学出品,计算机科学科普旗舰频道)
时长 约 10 分钟
播放量 百万级(Computerphile 经典热门视频)
核心主题 哈希函数原理、雪崩效应、密码存储与加盐

核心内容拆解

一、哈希函数的本质:一台单向搅拌机

视频开篇就给哈希函数下了一个精准的定义:它是一个确定性的、单向的"数字搅拌机"。你把任意长度的输入丢进去——一句话、一张图、一部两小时的电影——它都会吐出一个固定长度、看起来毫无规律的"指纹"。

这里有三个关键词,每一个都是后来所有安全设计的地基。确定性意味着同样的输入永远得到同样的输出,这是密码验证的前提:系统不需要知道你的密码,它只需要把你登录时输入的内容再哈希一次,对比两次指纹是否一致。固定长度意味着无论输入多长,SHA-256 永远吐 256 比特,这让存储和索引变得可控。而单向则是最关键的反直觉点:正向计算几乎瞬间完成,但想从指纹反推出原文,在数学上被认为是不可行的。

我的延伸分析是:很多人把"哈希"和"加密"混为一谈,根源就在这一步。加密是可逆的——用钥匙能解密还原;哈希是不可逆的——它是有损压缩,丢掉的信息永远找不回来。把密码"加密"存起来,等于默认了一把钥匙能打开所有人的秘密;而把密码"哈希"存起来,即便数据库整锅端走,攻击者拿到的也只是一堆无法逆推的指纹。视频用这个区分,直接判了"加密存密码"的死刑。

二、雪崩效应:一个比特翻转,整个指纹重写

视频最直观的一幕,是 Miles 博士拿出一份文档,算出它的哈希值,然后把其中一个不起眼的字符改掉一个字母——再算一次。结果是:整个指纹彻底变了,看不出任何规律。

这就是哈希函数的雪崩效应(avalanche effect):输入的微小变化,会被设计放大成输出的剧烈震荡。理想的哈希函数,输入改变 1 个比特,输出里每一个比特都有约 50% 的概率翻转。两份"看起来几乎一样"的内容,哈希出来却像两个毫不相干的随机串。

这一点为什么重要?因为它斩断了攻击者"猜相邻值"的捷径。如果输入改一点、输出也只改一点,攻击者就可以顺着指纹的变化梯度逼近原文——就像顺着等高线找山顶。雪崩效应把这个梯度彻底打乱,让指纹和原文之间看上去毫无几何关系。这也是为什么哈希能当"完整性校验"用:文件被改了一个字节,校验值立刻面目全非,篡改无处遁形。视频没有展开讲,但雪崩效应其实是一切抗篡改、抗预测设计的物理基础。

三、为什么"加密密码"是个危险的伪命题

视频把话锋一转,落到密码存储这个真正的痛点上。Miles 博士给出的第一原则非常硬:系统根本不应该有能力还原用户的密码。

如果你用对称加密(比如 AES)把密码加密后存进数据库,那就意味着系统里某处一定藏着那把解密钥匙。钥匙在配置文件里、在环境变量里、在某个密钥管理服务里——一旦它和数据库一起泄露,所有密码瞬间还原成明文,等于你帮攻击者做完了最后一步。更糟的是,加密存密码意味着你的系统"知道"用户密码,这违反了密码存储的零信任底线:任何一个能看到数据库或代码的内部人员,理论上都能反查所有用户密码,然后用它们去撞其他网站。

所以哈希在这里不是"另一种加密",而是一个根本不同的安全模型:系统验证密码,却从不持有密码;它持有的只是无法逆推的指纹。这是视频埋下的一颗认知炸弹——很多团队至今还在用"加密"思维对待密码,根源就是没迈过这道坎。

四、MD5/SHA 直接存:速度快,反而成了诅咒

理解了哈希的好处,紧接着就是视频点出的第一个大坑:不是所有哈希函数都适合存密码。MD5、SHA-1、SHA-256 这些"通用哈希",都是为速度设计的——它们要让 CPU、显卡尽可能快地算出指纹,用于文件校验、消息认证这些吞吐量优先的场景。

但速度对密码存储是致命的。视频暗示、而我要把话挑明的是:攻击者拿到一数据库的哈希后,最有效的手段就是暴力枚举——拿字典里的每个候选词、每个可能的字符串,逐一哈希,看是否撞上数据库里的某条记录。这时,哈希函数越快,攻击者每秒能试的次数就越多。现代一块消费级 GPU,用 hashcat 跑 MD5,每秒能算上千亿次(数百 GH/s 量级);这意味着一个 8 位纯数字密码(1 亿种组合)在不到一毫秒内就被穷举完毕,一个常见英文单词密码连一帧都撑不到。

这就是 SHA-256 直接存密码的悖论:你用一个为"快"设计的工具,去保护一个最需要"慢"的资产。视频把通用哈希和密码哈希区分为两件事,这是很多新手没意识到的关键——同一个算法,在不同场景下可能是安全神器,也可能是定时炸弹。

五、彩虹表:时间换空间的预计算字典

视频接下来展示了攻击者的下一件武器。如果直接用通用哈希存密码,攻击者甚至不需要实时暴力破解——他们可以提前把亿万个常见密码的哈希值算好,整理成一张巨大的"密码↔哈希"对照表,泄露时直接查表,毫秒级还原。

这就是彩虹表(rainbow table)的核心思想:用预计算的时间,换取实时破解的空间。它的巧妙之处在于用"哈希链"和"归约函数"大幅压缩存储——不需要把每个密码都存下来,而是用链式结构,只存链首链尾,中间靠计算还原。即便如此,一张覆盖常见密码的彩虹表也就几十上百 GB,一张硬盘装得下,二手就能买到。

视频传递的危机感是真实的:当你看到 6500 万个 RockYou 明文密码泄露、成为全世界攻击者的默认字典时,就会明白为什么"用 SHA 存密码"等于把锁挂在门把手上。任何在数据库里出现两次的相同哈希值,都暴露了两个用户用了同一个密码——而最常见的几个密码,彩虹表里早已备好。

六、加盐:给每个密码一个独立宇宙

视频给出的第一道防线,就是加盐(salting)。思路朴素却致命:在哈希之前,给每个用户的密码拼接一段随机字符串(盐),然后再哈希。这段盐和哈希一起明文存进数据库,不需要保密。

加盐的魔力在于它让彩虹表瞬间作废。攻击者预先算好的彩虹表,是针对"裸密码"的;可一旦每条记录都掺了不同的盐,同一个密码 "password123" 在用户 A 那里变成 hash("password123" + 盐A),在用户 B 那里变成 hash("password123" + 盐B),两个指纹完全不同。攻击者再也没法用一张通用彩虹表通吃整个数据库——他必须为每一个盐值,重新生成一张专属彩虹表,预计算成本爆炸到不现实。

更重要的是,盐让"撞库"失效:即使两个用户密码相同,数据库里也看不到重复的哈希值,攻击者无法通过统计高频哈希来批量识别弱密码。视频用这个细节点出了安全设计的一个深刻哲学——你要消除的,不是单个密码的脆弱,而是整个系统里可被批量利用的模式。盐打掉的就是这种可批量化的捷径。

不过视频也隐含了一个前提,我要强调:盐必须是每个用户独立、足够长且用密码学安全的随机数生成。用用户名当盐、用时间戳当盐、全系统共用一个盐,都是常见的翻车姿势——前者可预测,后者等于没加。

七、慢哈希:把暴力破解拖进泥潭

加盐解决了彩虹表,却没解决暴力破解——攻击者仍然可以针对某条记录,用 GPU 逐个候选词加同样的盐、哈希、比对。视频停在加盐这一步,而现实世界的第二道、也是更关键的防线,是故意把哈希变慢:bcrypt、scrypt、argon2 这一类密码哈希函数(password hashing function)。

它们的反直觉之处在于:工程师一辈子都在追求"快",而它们的设计目标恰恰是"慢得恰到好处"。bcrypt 靠一个工作因子(cost / work factor)参数,让算法反复迭代——cost 每加 1,哈希时间翻倍。在服务器上调到 cost=12 左右,单次验证大约要几百毫秒:对一个真实用户登录,这点延迟毫无感知;但对一个每秒想试上千亿次密码的攻击者,这个延迟就是绞索——同样的 GPU,从每秒千亿次直接被打到每秒几万次,攻击成本暴涨六七个数量级。

argon2(2015 年 Password Hashing Competition 的冠军)更进一步,引入了内存硬化:它要求哈希过程占用一大块内存(几十上百 MB)。这招专门克制 GPU 和 ASIC——它们算力惊人,但每个计算核心能访问的内存很小,强行让它们搬运大块数据,性能优势立刻归零。OWASP 如今推荐的首选就是 argon2id。这一脉的演进逻辑非常清晰:既然攻击者的武器是"快",那么密码哈希的全部艺术,就是用 CPU 时间和内存空间,兑换成攻击者无法负担的成本。

八、碰撞攻击:SHA-1 的倒塌

最后,视频提到的哈希另一个性质——抗碰撞性——在现实里也有保质期。一个安全的哈希函数,应该让"找到两个不同输入产生相同指纹"这件事难到不现实。但 2017 年 Google 的 SHAttered 研究,用约 6500 个 CPU 年和 110 个 GPU 年的算力,首次公开碰撞了 SHA-1:两份内容不同的 PDF,拥有完全相同的 SHA-1 指纹。

这宣告了 SHA-1 作为安全哈希的终结。对密码存储而言,碰撞攻击的直接威胁没那么大(攻击者要先算出某个明文密码的碰撞才有用,这在登录场景里意义有限),但它说明了一个更根本的道理:密码学哈希是一场军备竞赛。MD5 早在 2004 年就被王小云团队碰撞,SHA-1 在 2017 年倒塌,今天 SHA-256 仍是主流但也在被持续审视。这也是为什么存密码必须用专门演进、可调参数的密码哈希函数,而不是把宝押在某个"目前还没被破"的通用哈希上——你需要的是一种能随着硬件进步不断加码的设计,而不是一个会突然过期的常数。

知识结构图

flowchart TD
    A["存密码的正确姿势"] --> B["核心原则:系统能验证\n却无法还原密码"]
    B --> C["哈希 vs 加密"]
    C --> D["加密:可逆\n→ 钥匙泄露=全军覆没 ❌"]
    C --> E["哈希:单向\n→ 拿到指纹也逆推不了 ✅"]

    E --> F["第一道防线:加盐 Salt"]
    F --> F1["每用户独立随机盐"]
    F --> F2["让彩虹表作废\n消除重复哈希模式"]

    E --> G["第二道防线:慢哈希"]
    G --> G1["bcrypt\n工作因子 cost,迭代翻倍"]
    G --> G2["argon2id\n内存硬化,克制 GPU/ASIC"]

    H["常见错误"] --> H1["明文存储"]
    H --> H2["MD5/SHA 直接存\n速度=攻击者武器"]
    H --> H3["加密存密码\n钥匙=单点崩溃"]

    F2 --> I["攻击模型"]
    G1 --> I
    I --> J["暴力枚举 / 字典 / 彩虹表"]
    J --> K["防御逻辑:用 CPU 时间 + 内存\n兑换攻击者无法承担的成本"]

实战启示:从今天起,重新审视你的密码存储

这支视频最大的价值,是把"密码存储"从一个被随手处理的细节,提升成了一个有清晰攻防逻辑的系统问题。看完之后,至少能带走几条可立即执行的检查清单。

第一,给现有系统做一次"密码字段体检"。 打开你的用户表,看一眼密码那列存的是什么。如果是明文、Base64、或看起来短得可疑的固定串(典型 MD5 是 32 位十六进制),立刻拉响警报。如果是 SHA-256 没加盐、或全系统共用一个盐,也属于高风险。理想的长相是 bcrypt 的 $2b$cost$... 或 argon2 的 $argon2id$... 格式——盐和参数都自包含在哈希字符串里。

第二,永远不要自己发明密码哈希方案。 别把 SHA256(salt + password) 这种"看起来很对"的拼接直接用进生产——它仍然是通用哈希,仍然太快。直接调用成熟的库:Node 用 bcrypt 或 argon2,Python 用 passlib 或 argon2-cffi,Go 用 golang.org/x/crypto/bcrypt。让库帮你处理盐的生成、参数协商、常量时间比较这些容易写错的细节。

第三,把 cost 参数当成需要逐年维护的配置。 bcrypt 的 cost、argon2 的 memory 和 iterations 不是一次设好就永远对的——摩尔定律会让今天"够慢"的设置在五年后变快。建议每年用当时的硬件重新基准测试,把单次哈希时间维持在几百毫秒这一档。argon2id 可以借助其内嵌的参数迁移机制平滑升级已有哈希:用户下次登录时,用更强的参数重新哈希并替换旧值。

第四,从根本上减少需要保护的密码数量。 尽可能接入 OAuth / Passkey / WebAuthn 这类无密码方案。当你不需要存任何密码时,整条攻击链就从源头消失了——这是比任何哈希算法都更彻底的防御。Computerphile 没讲这一层,但它是这段攻防叙事的最终归宿。

最后一点认知升级:哈希函数的"快"和"慢"从来不是好坏之分,而是场景之分。同一个 SHA-256,在验证文件完整性时是优点,在存密码时是灾难。理解一个工具为什么被设计成这样,比记住"该用它"重要得多——这才是看完这支视频真正的收获。

延伸学习路径

  1. OWASP Password Storage Cheat Sheet — 工业界密码存储的事实标准,直接给出 argon2id 的推荐参数和工作因子基准,是落地实现的第一参考。
  2. Computerphile 频道其他安全短片 — 如 How HTTPS Works、Public Key Cryptography,与本片同源,构成完整的密码学入门拼图。
  3. SHAttered(shattered.io) — Google 公布 SHA-1 碰撞的研究页面,附论文与可下载的碰撞 PDF,亲手感受"抗碰撞"保质期的尽头。
  4. 《Serious Cryptography》Jean-Philippe Aumasson 著 — 进阶读物,深入讲解哈希函数内部构造(海绵结构、Merkle-Damgård)以及它们如何被攻击。
  5. LearnThatStack《You're Storing Passwords Wrong. Here's The Fix》 — 一个更聚焦现代实践的补充视角,与 Computerphile 的概念讲解互补。

一句话总结

密码存储的全部艺术,就是用"单向、加盐、故意变慢"三件套,把攻击者的时间成本和内存成本抬到不可承受——让系统能验证密码,却永远无法知道密码。

参考来源

  1. Hashing Algorithms and Security — Computerphile — 本文深度解读的核心视频
  2. OWASP Password Storage Cheat Sheet — 工业界密码存储最佳实践与 argon2id 推荐参数
  3. SHAttered: The first public SHA-1 collision — Google 公布的 SHA-1 碰撞研究
  4. PHC Winner: argon2 — 2015 年密码哈希竞赛冠军 argon2 官方实现

本文由「51学通信」技术团队出品。51学通信由通信行业18年老兵爱卫生(微信ID: gprshome201101)维护,聚焦5G/6G核心网、3GPP标准解读、通信前沿技术深度分析。 出版作品有《5G核心网原理与实践》《IMS原理与实践》等4本通信专业书籍。知识星球「51学通信」提供深度技术答疑和行业洞察。

[!tip] 51学通信知识星球 星主:爱卫生(微信:gprshome201101)——公众号「51学通信」创办者,19 年通信行业运维与讲师经验,著有《GPRS网络信令实例详解》《EPC原理与实践》《5G核心网原理与实践》三本纸质书(各大电商平台有售)。 星球定位:深耕 5G 核心网、IMS、NFV/AI、云原生等 ICT 领域,主打运维岗位与信令分析。 当前规模:5200 篇主题 / 990 个回答,198 元/年。 加入福利:加入星球后请加爱卫生微信,拉您进知识星球年度陪伴与答疑群——不限量回复您的各种问题,另有群内分享。 AI 加持:51学通信知识星球已作为 skill 接入 WorkBuddy,使用 deepseek-4-flash 在海量星球帖子中精准找贴、找视频、找 FAQ 和案例,做总结、找文档和 PPT 等场景全覆盖。

51学通信知识星球海报-扫码加入