一句话概括
哈希函数就是一个数字绞肉机,无论你喂给它什么数据——一个字符、一部 4K 电影、还是整个美国国会图书馆——它都能把它变成一串短小、唯一、固定长度的乱码。
它解决了什么问题
早在我们拥有千兆互联网之前,就有一个简单而古老的问题:你怎么知道一条消息或一个物件是真实的,没有被篡改过?国王们用玺戒在热蜡上按下一个独特的印章。如果印章完好无损,卷轴就是合法的。这是一种物理上的“完整性检查”。
在数字世界里,我们不能用蜡。早期的计算机科学家使用简单的“校验和”(checksum)来验证通过嘈杂线路发送的数据没有被随机的电子小妖怪损坏。校验和是数据的一个简单数学摘要。如果发送方和接收方为同一个文件计算出相同的校验和,那它很可能是同一个文件。但这些简单的校验和很容易被愚弄。攻击者可以修改数据,同时让其产生完全相同的校验和。这个数字蜡封很脆弱。
我们需要更强的东西。我们需要一个数字指纹。一个能为数据创建摘要的函数,这个摘要不仅是确定性的(相同的文件总能产生相同的指纹),而且几乎不可能被逆向工程或伪造。如果你哪怕只改变输入数据的一个比特(bit),产生的指纹也应该变得面目全非且无法预测。
这就是加密哈希函数的任务。它提供了一种强大、计算上安全的方式来验证数据完整性,回答了这个关键问题:“这东西到底是不是你发给我的那个东西?”
底层工作原理
哈希函数的核心是一种数学算法。你不需要密码学博士学位也能使用它,但理解其关键属性是区分脚本小子和老鸟工程师的关键。
### 核心属性
一个好的加密哈希函数就像一个值得信赖但又超级古怪的朋友。它有几个不容商量的性格特点:
- 确定性 (Deterministic): 它不是随机的。给它相同的输入一百万次,它每次都会吐出完全相同的哈希值。没有例外。
- 抗原像攻击 (Pre-image Resistance / One-Way): 这就是“你无法把炒熟的鸡蛋变回生鸡蛋”的属性。给定一个哈希值,从计算上来说,找出创建它的原始输入是不可行的。这就是为什么我们可以存储密码的哈希值而不是密码本身。
- 抗第二原像攻击 (Second Pre-image Resistance): 给定一个输入及其哈希值,从计算上来说,找到一个不同的输入产生相同的哈希值是不可行的。这可以防止攻击者用一个具有相同哈希值的恶意文件来替换合法文件(比如
install.exe)。 - 抗碰撞性 (Collision Resistance): 从计算上来说,找到任意两个不同的输入哈希到同一个输出是不可行的。这是最强的属性。在一个像 SHA-256 这样的优秀算法中,偶然找到一个碰撞的概率,比地球在未来五秒内被黑洞吞噬的可能性还要小。
### 雪崩效应
哈希函数最酷到令人发指的特性之一就是雪崩效应。对输入的微小、不起眼的更改,会导致输出哈希值发生巨大、不可预测的变化。它不是渐进式变化,而是完全重新洗牌。
让我们用流行的 SHA-256 算法来看看实际效果:
| 输入字符串 | SHA-256 哈希输出 |
|---|---|
Hello world |
b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9 |
hello world |
7509e5bda0c762d2bac7f90d758b5b2263fa01ccbc542ab5e3df163be08e6ca9 |
Hello world. |
f4bb2dd13b43a3509ba3a5a73b40d046f564f1f31d428a113d420f185c7a312f |
注意,改变一个大写字母或添加一个句点,创建出的哈希值与原来的完全没有任何相似之处。这个属性至关重要。这意味着攻击者不能只是稍微调整一下文件,就指望能产生一个看起来相似的哈希值。
### 从 MD5 到 SHA:一部简短的家族史
并非所有哈希函数都是生而平等的,和所有技术一样,它们也会变老。
MD5 (Message Digest 5): 老黄牛。在很长一段时间里,MD5 曾是山丘之王。它产生一个 128 位的哈希值(32 个十六进制字符)。它速度快,曾被认为是安全的。曾经是。 2004 年,研究人员演示了一种在 MD5 中寻找碰撞的实用方法。如今,MD5 在密码学上被认为是已被攻破的,绝不应该用于安全目的,如密码存储或数字签名。它对于非安全性的校验和仍然可用,比如检查文件下载是否正确。
SHA-1 (Secure Hash Algorithm 1): MD5 的继任者,产生一个 160 位的哈希值。多年来它一直是标准,从 SSL 证书到 Git 都在使用。但败局已定。2017 年,Google 宣布了首次实际的 SHA-1 碰撞。和 MD5 一样,它现在也被认为是不安全的,并已在加密用途中被弃用。
SHA-2 (Secure Hash Algorithm 2): 这不是单一算法,而是一个家族,包括广泛使用的 SHA-256 和 SHA-512。它们产生更长的哈希值(分别为 256 位和 512 位),并采用更强的设计。截至今日,SHA-2 是行业标准,被认为在所有常见用途中都是安全的。
SHA-3: 一个全新的设计,从 NIST 主办的一次公开竞赛中选出。它不是为了取代 SHA-2(SHA-2 仍然安全),而是为了在 SHA-2 家族万一被发现缺陷时,提供一个强大的、结构上完全不同的替代方案。
真实世界的故事
### 损坏的下载文件案
DevOps 工程师 Maria 正在配置一台新服务器。她需要下载最新 Ubuntu LTS 版本的 8GB 镜像。官方网站提供了 ISO 文件,旁边还附带了一个 SHA-256 哈希值。下载完成了,但当她尝试从镜像启动时,却出现了一个神秘的错误。她越来越沮丧。然后,她想起了那个哈希值。她用自己机器上的哈希生成器处理了下载的 ISO 文件。输出结果与 Ubuntu 网站上的哈希值不符。文件在下载过程中损坏了——这里或那里翻转了几个比特。她删除了损坏的文件,重新下载了一次,这次,她做的第一件事就是验证哈希。完美匹配。安装顺利进行。
教训: 哈希是你抵御数据损坏的第一道防线,能为你省去数小时调试神秘错误的时间。
### 代码库里的幽灵提交
一个软件团队陷入了恐慌。他们的线上应用发现了一个严重的安全漏洞。查看代码后,似乎一个关键文件中的权限检查被巧妙地移除了。但这是谁干的,又是什么时候干的?团队负责人 David 求助于他们的 Git 历史。Git 的底层其实就是一个巨大的哈希系统。每个文件、每个目录结构、每次提交都由一个 SHA-1 哈希值来标识。David 写了一个小脚本,重新计算了那个特定文件在仓库历史中每次提交时的哈希值。他找到了文件哈希值突然变成漏洞版本的那个确切提交。提交信息看起来很无辜,但哈希值揭示了真相。他们找到了罪魁祸首和时间线。
教训: 哈希提供了一个不可篡改、可验证的审计追踪,构成了现代版本控制的基石。
### 没有被盗的密码
一家创业公司的用户数据库被攻破。攻击者窃取了整个 users 表。CEO 吓坏了,脑海中浮现出数百万密码泄露的新闻头条。但首席安全工程师 Aisha 却很冷静。“他们没有拿到密码,”她说,“他们拿到的是哈希值。”当用户注册时,系统并没有存储他们的密码 p@ssword123。相反,系统将密码通过一个安全的哈希算法(并加上“盐 (salt)”,一个至关重要的额外步骤)处理,生成了类似 ef92... 的东西。当用户登录时,系统会哈希他们刚刚输入的密码,并与存储的哈希值进行比较。由于抗原像攻击的特性,拥有数据库转储的攻击者无法将 ef92... 变回 p@ssword123。用户账户是安全的。
教训: 永远、永远、永远不要存储明文密码。要存储它们加盐后的安全哈希值。
常见的错误和陷阱
- 将已破解的算法用于安全场景。 仅仅因为某个工具能生成 MD5 或 SHA-1 哈希,不代表你就应该用它们来做新的安全关键型工作。它们用于校验和没问题,但对于密码或签名,请坚持使用 SHA-256 或更强的算法。
- 混淆哈希与加密。 它们是用于不同工作的不同工具。哈希是用于验证完整性的单行道。加密是用于保护机密性的双行道。你可以“解密”一条加密消息,但你无法“反哈希”一个哈希值。
- 忘记使用盐 (salt)。 直接哈希密码是不够的。如果两个用户有相同的密码,他们就会有相同的哈希值。攻击者使用预先计算好的“彩虹表 (rainbow table)”来查找常用密码的哈希。 “盐”是在哈希之前添加到每个密码中的唯一随机数据,这使得这些攻击变得无效。
- 相信来自不可信来源的哈希值。 哈希只能证明数据自被哈希以来没有改变。如果你从
malicious-site.com下载了一个恶意文件,而他们也为它提供了一个哈希值,那么这个哈希值将与他们的恶意文件完美匹配。哈希值必须从一个独立的、可信的来源获取(比如通过 HTTPS 访问的官方开发者网站)。
为什么它值得你关注
作为一名开发者,哈希是你将不断遇到的一个基本概念。每当你需要做以下事情时,都应该想到哈希:
- 验证文件完整性: 在提供或使用下载文件时。
- 存储用户凭证: 哈希是现代密码安全的基础。
- 使用版本控制: 像 Git 这样的系统是建立在哈希的基石之上的。
- 构建 API: HTTP 的
ETag头部通常使用资源内容的哈希值来实现高效缓存。 - 检测变化: 需要知道一大块数据是否已更改,但又不想存储两份副本?存储数据及其哈希值。要检查更改,只需重新哈希并进行比较。
- 理解区块链: 加密货币和区块链使用哈希将区块链接在一起,形成一个不可变的账本。
哈希不仅仅是一个小众的加密工具;它是一个用于创建可靠、安全和高效软件的通用构建模块。
深入了解
- Wikipedia: Cryptographic hash function - 关于哈希函数是什么及其属性的权威性高阶概述。
- FIPS PUB 180-4: Secure Hash Standard (SHS) - NIST 发布的官方标准,它定义了 SHA-1 和 SHA-2 家族算法。内容很密集,但它是第一手资料。
- The SHAppening: freestart collisions for SHA-1 - 来自 Google 和 CWI 研究团队的网站,他们宣布了首次公开的 SHA-1 碰撞,并附有示例。一篇关于旧算法为何消亡的精彩读物。
- Troy Hunt: Everything you ever wanted to know about building a secure password reset feature - 这篇由顶尖安全专家撰写的文章虽然是关于密码重置的,但它深入探讨了为何以及如何正确哈希密码的实践细节。
- MD5 Considered Harmful Today - 详细介绍了一个研究项目,该项目演示了针对 MD5 的实际碰撞攻击,创建了一个流氓证书颁发机构。