Hash function 在网络安全里是个无处不在的概念——存密码、verify 文件、git commit、区块链——都建在它上面。但它确实是密码学里最反直觉的概念之一。我用 5 层讲透,从最具象到最抽象。
第 1 层:用一个生活类比开始
想象你在做一道菜——比如红烧肉。
你把所有食材(五花肉、酱油、糖、八角、姜……)一起放进锅里,炖 2 小时。最后端上桌——这就是一道红烧肉。
现在问你两件事:
- 问题 1:给定食材 → 能不能做出红烧肉? → 可以,跟着步骤做就行。
- 问题 2:给定一盘做好的红烧肉 → 能不能还原出”用了多少肉、多少酱油、多少糖”? → 几乎不可能。你尝得出咸度,但说不出确切克数。倒过来推每一种原料各多少,做不到。
Hash function 就是这个”做菜”过程的数学版:
| 现实 | 数学 |
|---|---|
| 食材(五花肉 / 酱油 / 糖) | 数据(任何文件、字符串、密码) |
| 做菜步骤(炖 2 小时) | Hash 算法(SHA-256、MD5) |
| 那盘做好的菜 | Hash 值(那一串十六进制字符) |
核心特性:做容易,反向推不出来。
第 2 层:看一眼真实的 hash 长什么样
我让你看几个具体例子,你立刻有手感:
输入: "hello"
SHA-256: 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
输入: "Hello" ← 只改了第一个字母大小写
SHA-256: 185f8db32271fe25f561a6fc938b2e264306ec304eda518007d1764826381969
输入: "hello world"
SHA-256: b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9
输入: "hello" ← 跟第一个一模一样
SHA-256: 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
你看到了什么?
- 观察 1 —— 每个 hash 长度都一样(64 个字符)。不管你输入”hello”还是输入整本《红楼梦》,SHA-256 输出永远是 64 个字符。
- 观察 2 ——
hello和Hello只差一个字母大小写,hash 完全不一样。不是改 1/5,是 100% 不一样。 - 观察 3 —— 同样的输入
hello,永远产生同样的 hash。这不是随机,是确定的。 - 观察 4 —— 看 hash 你猜不出原文。你看到那一串
2cf24dba...,没有任何线索告诉你原文是”hello”。
第 3 层:hash 的 5 个特性(套到”菜”上)
| # | 特性 | 数学定义 | 红烧肉类比 |
|---|---|---|---|
| 1 | 确定性 | 同样输入永远同样输出 | 同样食材 + 同样步骤,永远做出同样味道 |
| 2 | 单向性 | 从 hash 反推原文 → 做不到 | 给你菜,推不出每种食材的精确克数 |
| 3 | 雪崩效应 | 输入改一点点 → 输出完全不同 | 多放一勺盐 → 整盘菜味道全变 |
| 4 | 固定长度 | 不论输入多长,输出长度固定 | 不管放多少食材,最后都是一盘菜 |
| 5 | 抗碰撞 | 两个不同输入产生同 hash → 几乎不可能(参见 hash collision) | 两道菜口味完全一致 → 几乎不可能 |
第 4 层:这玩意儿到底有什么用
Hash function 单看很奇怪——做容易做、反推不出来。这有啥用?
它有 3 个核心用途,你天天都在用,只是没意识到。
用途 1:验证文件没被篡改(完整性 = CIA 中的 I)
情景:你公司内网有个程序 invoice.exe,大家都用。某天攻击者偷偷换成了一个植入后门的版本。程序还能正常用,功能一模一样,但每次运行偷偷传数据出去。
你怎么知道程序被换了?
- 直接看文件大小 —— 攻击者可以保持文件大小一样
- 直接看文件名 —— 文件名根本没变
- 打开看内容 —— exe 是二进制,看不出来
用 hash:
原版 invoice.exe → SHA-256 → A1B2C3D4...E5F6 (确定的 64 字符)
被改 invoice.exe → SHA-256 → 9X8Y7Z6W...3M2N (完全不一样)
每周自动算一次 hash,跟存档的对比——只要变了,说明文件被改过。
→ 这就是为什么 npm 安装包、Docker image、Linux 发行版下载页,永远都贴一个 SHA-256 值:
ubuntu-22.04.iso
SHA-256: a4acfda10b18da50e2ec50ccaf860d7f20b389df8765611142305c0e911d16fd
下载完后你自己算一遍 hash,和官方贴的对比。一样 = 没被人调包;不一样 = 立刻删了别用。
这就是 不可否认性 —— 你没法假装文件没改过,因为 hash 会出卖你。
用途 2:存密码(机密性 = CIA 中的 C)
这个用途比第一个更日常,但也更反直觉。
问题:网站需要验证你的密码,那密码到底怎么存?
❌ 错误方案 1:明文存
数据库:
shawn@auplus.com.au | 我的真密码123
→ 数据库被脱库 = 所有人密码全暴露。史诗级灾难。
❌ 错误方案 2:加密存
数据库:
shawn@auplus.com.au | AES加密(我的真密码123) | key=xxxx
→ 看起来安全。但攻击者也能拿到 key(他都进数据库了),然后全解开。 → 而且——网站根本不需要”知道”你的密码,只需要”验证”它。
✅ 正确方案:hash 存
数据库:
shawn@auplus.com.au | SHA-256("我的真密码123") = a1b2c3d4...
你登录的时候发生了什么:
1. 你在浏览器输入"我的真密码123"
2. 浏览器/服务器对这个输入计算 hash
3. 算出来的 hash = a1b2c3d4...
4. 跟数据库存的 hash 对比
5. 一样 → 让你进;不一样 → 拒绝
这套设计的天才之处:
- 数据库永远不存原密码
- 即使数据库被脱库,攻击者拿到的也只是 hash 值,不是密码
- 攻击者反推不出原密码(单向性)
- 但你下次登录还能正常验证(确定性 + 同输入 = 同输出)
→ 网站从来不”知道”你的密码,但它能”验证”你的密码。 这就是 hash 的魔力。
这也解释了为什么:当你点”忘记密码”,网站让你”重设”,而不是”告诉你原密码是什么”——因为他们真的不知道。能直接告诉你原密码的网站,99% 是用明文存的,赶紧跑。
⚠️ 真实生产代码不是裸 SHA-256。为了防”彩虹表”等攻击,密码 hash 要加 salt(每个用户独立的随机字符串混进密码再 hash)+ 用 argon2 这类故意慢的算法。但这是另一个话题——本文讲的是 hash function 本身。
用途 3:数据指纹 / 版本标识
你天天用 git,每个 commit 都有一个 hash:
$ git log
commit a1b2c3d4e5f6...
fix: 修复登录 bug
commit 9x8y7z6w5v4u...
feat: 添加 MFA 支持这个 hash 不是随机生成的——它是把整个 commit 的内容(代码 + 上一个 commit 的 hash + 时间 + 作者……)全部 hash 出来的。
所以:
- 任何人改一行代码 → commit hash 立刻变
- 甚至改了 commit message → hash 也变
- 整个 git 历史像锁链一样环环相扣——改动任何一个 commit,后面所有 commit 的 hash 都会变,被一眼识破
→ 这就是为什么 git 能保证版本可追溯、不可篡改。它的根基是 hash。
(顺便,区块链就是这个原理扩大化——每个区块的 hash 包含前一个区块的 hash,串成不可篡改的链。)
第 5 层:加密 vs 哈希,最后一次区分
讲到这里,你应该能自己回答这个问题了:
加密和哈希有什么区别?
| 加密 | 哈希 | |
|---|---|---|
| 目的 | ”存起来,有人能取出来”(给授权的人看) | “存起来,谁动过都知道”(验证完整性 / 验证身份) |
| 方向 | 双向:加密 ↔ 解密 | 单向:只能算出来,算不回去 |
| 用 key? | ✅ 用 key(对称一把,非对称两把) | ❌ 不用 key |
| 保护 CIA 哪个字母? | C(机密性) | I(完整性)+ 间接保护 C(密码存储场景) |
| 输出长度 | 输出长度 ≈ 输入长度 | 输出长度固定,跟输入无关 |
| 实际工具 | AES-256 / RSA / TLS | SHA-256 / bcrypt / MD5 |
记忆口诀:
加密 = “可逆的锁,有钥匙能开” 哈希 = “不可逆的搅碎机,只能比对碎片”
看到 AI 给你写涉及 hash 的代码,1 个问题就能审
AI 替你写处理密码 / 验签 / 完整性校验的代码时,看到 hash 类调用先问:
它在做”算 hash”还是”对比 hash”?
- 算 hash —— 输入数据 → 输出 hash 字符串,存起来
- 对比 hash —— 同样的算法重算一遍,跟存的对比
一切都是这两件事的组合。看懂这一点,你看 AI 写的密码学相关代码就有了脚手架。
相关阅读
- PII 4 条铁律 —— hash 的”存密码”用途就是第 1 条静态加密的最常见落地
- 数据分级与 5000 美元 SSH key —— 真实事故里 hash 出场的方式
- 漏洞 公式 —— hash 漏洞(算法被破)如何抬升整体风险
Hash 不是魔法,它就是”一锅炖好的菜”。 你能尝出味道,但说不出每种食材的克数——这朴素的不对称,撑起了密码学的半边天。