如何生成 MD5、SHA-256 等哈希
哈希把任何输入(一个密码、一个文件、一条消息)转换为固定长度的字符串。同一输入总产生同一哈希,而即使是输入中最微小的变化也会产生完全不同的哈希。这使哈希成为完整性验证、密码存储、数字签名、区块链证明以及现代计算十几种其他基石的必备。选对算法、知道为什么有些已被攻破、并辨认出滥用哈希的模式,会让一个五秒钟的小工具变成可以安全立足其上的基础。
哈希函数简史
作为编程概念的哈希比密码学早了数十年,数据结构里的哈希表使用 CRC、FNV 等简单函数把键散布到桶里。设计成不可逆且抗碰撞的密码学哈希,出现于 1980 年代末:Ron Rivest 的 MD4(1990)与 MD5(1991)。MD5 成为事实标准长达二十年,直到实用碰撞使其在安全场景中不再可用。
NIST 的 SHA-0(1993)几乎立即被撤回,由 SHA-1(1995)替代。SHA-1 撑得更久,但分阶段被攻破:2005 年的理论攻击、2009 年具备实际意义的证书伪造场景、2017 年 Google 的 SHAttered 演示,两份不同的 PDF 拥有相同的 SHA-1 哈希。2001 年发布的 SHA-2 家族(SHA-224、SHA-256、SHA-384、SHA-512)被设计为更长期的替代者,至今仍然安全。SHA-3(Keccak,2015 年标准化)在结构上不同,目的是在 SHA-2 倒下时提供后备。
与此并行,面向密码的哈希则单独演化。纯 MD5 或 SHA-1 用于密码存储太快,于是 bcrypt(1999)、scrypt(2009)与 Argon2(2015,密码哈希竞赛胜出者)添加了刻意的慢与内存难度,把暴力破解的成本提升了数个数量级。对密码合适的哈希,从来都不是对文件校验合适的那个。
哈希如何工作
哈希函数接收任意大小的输入,产出固定大小的输出:
| 输入 | SHA-256 哈希(前 16 个字符) |
|---|---|
| hello | 2cf24dba5fb0a30e... |
| Hello | 185f8db32271fe25... |
| hello! | ce06092fb948d9ff... |
注意,把一个字符从小写 h 改为大写 H,或者添加一个字符,哈希就完全变了。这叫雪崩效应,正是它让哈希善于捕捉任何细小变化。
在内部,现代哈希函数把输入切成固定大小的块(SHA-256 是 64 字节,SHA-512 是 128 字节),让每个块通过压缩函数,并把状态向前链接。输出是最后一块混入后的最终状态。由于链依赖于每一个字节,没有捷径能让攻击者在不重写整个哈希的情况下修改输入。
一个好的密码学哈希具备三个安全性质:抗原像(你找不到能产生给定哈希的输入)、抗第二原像(给定一个输入,你找不到另一个产生同一哈希的输入)以及抗碰撞(你找不到任意两个不同的输入产生同一哈希)。MD5 三者全失;SHA-1 失去抗碰撞;SHA-2 与 SHA-3 仍保有三者。
常见哈希算法
| 算法 | 输出位数 | 输出长度 | 状态 | 用途 |
|---|---|---|---|---|
| MD5 | 128 | 32 个十六进制字符 | 已破(不安全) | 遗留校验、非安全用途 |
| SHA-1 | 160 | 40 个十六进制字符 | 已破(不安全) | 仅限遗留系统 |
| SHA-224 | 224 | 56 个十六进制字符 | 安全(小众) | 建议优先 SHA-256 |
| SHA-256 | 256 | 64 个十六进制字符 | 安全 | 文件完整性、数字签名 |
| SHA-384 | 384 | 96 个十六进制字符 | 安全 | TLS 1.3 套件 |
| SHA-512 | 512 | 128 个十六进制字符 | 安全 | 高安全应用,64 位性能 |
| SHA3-256 | 256 | 64 个十六进制字符 | 安全 | SHA-256 的前瞻替代 |
| BLAKE2b / BLAKE3 | 256 或 512 | 可变 | 安全且非常快 | rsync、restic、批量哈希 |
| HMAC-SHA256 | 256 | 64 个十六进制字符 | 安全 | API 请求签名 |
| bcrypt | 184 | 60 个字符(自定义) | 对密码安全 | 密码存储 |
| Argon2id | 可配置 | 可变 | 密码最佳 | 现代密码存储 |
| CRC32 | 32 | 8 个十六进制字符 | 仅错误检测 | 不是安全哈希 |
大多数通用用途下,SHA-256 是当前标准。MD5 与 SHA-1 仅应在必须与需要它们的遗留系统交互时使用,绝不用作安全边界。对密码,使用 bcrypt 或 Argon2id,而不是原始 SHA-256。
如何生成哈希
- 选择算法:在下拉框中选 MD5、SHA-1、SHA-256、SHA-384 或 SHA-512。除非有特定原因选其它,否则用 SHA-256。
- 输入文本或上传文件:在输入框里键入或粘贴文本,或拖入一个文件。该工具用 Web Crypto API 完全在你的浏览器中运行。
- 复制哈希:结果是十六进制字符串,可用于验证、存储或比较。许多工具还提供 base64 编码以紧凑存储。
- 需要时比较:把已发布哈希粘到生成哈希旁,让工具标出第一个不同字符。肉眼比对 64 字符字符串容易出错。
实际用途
文件完整性验证:下载一个文件,把其哈希与发布者的官方哈希对比。若一致,文件就是真实且未损坏的。这是日常哈希生成最常见的用例,Linux 上每一次 sha256sum 的背后,以及每一个软件下载页上的校验和页面,都是这一流程。
密码存储,应用存储的是密码的哈希而非密码本身。当你登录时,你的输入会被哈希并与已存哈希对比。关键点在于算法必须故意放慢(bcrypt、Argon2),以使盗走哈希文件的攻击者无法在合理时间内暴力破解。
数据去重:存储系统和备份工具会对数据块(常是几兆字节)进行哈希,并把哈希用作键。具有相同哈希的两块被视作相同,因此第二次出现仅存指针。restic、borg 以及许多云备份服务都依赖此原理。
数字签名:数字签名是被私钥加密的哈希。验证者对文档哈希、用公钥解开签名,核对两者是否一致。这既证明文档没有改动,也证明签名者批准了正是这一版。
用于 API 安全的 HMAC:HMAC 将哈希函数与密钥结合,产出一个任何持有相同密钥者都能验证的标签。Webhooks、AWS 请求签名以及许多内部 RPC 都用 HMAC-SHA256,以便接收方知道请求确实来自可信来源。
区块链与 Merkle 树:加密货币、内容寻址存储(IPFS)和 Git 都使用哈希树,以一个根哈希对庞大数据集做出承诺。在树中任何地方改动一个字节,根哈希都会变,这正是数据具备防篡改性的性质。
缓存键:缓存系统对请求 URL 或查询参数做哈希,生成紧凑的查找键。这里常见 CRC 与 SipHash,因为它们更看重速度而非密码学保证。
哈希 vs HMAC vs 数字签名
由于三者都输出形状相似的十六进制字符串,常被混淆。
| 概念 | 输入 | 验证什么 | 常见用途 |
|---|---|---|---|
| 哈希 | 数据 | 自哈希计算以来数据未变 | 校验和、内容寻址 |
| HMAC | 数据 + 共享密钥 | 数据未变 且 由持有密钥者创建 | API 请求签名、webhooks |
| 数字签名 | 数据 + 私钥 | 数据未变 且 由特定密钥签署 | TLS 证书、软件签名 |
| 加密 | 数据 + 密钥(任意) | 数据在传输中保持机密 | 保密性(不只是完整性) |
纯哈希并不能证明谁创建了它。HMAC 证明发送方掌握共享密钥。签名进一步在无需共享密钥的情况下识别签名者。选择能解决你实际问题的最弱工具。
常见陷阱
- 把 MD5 或 SHA-1 用于安全,两者在密码学上都已被攻破。MD5 几秒就可生成碰撞,SHA-1 在云硬件上数小时可达。严格保留它们于非安全校验。
- 用通用哈希给密码做哈希,纯 SHA-256 哈希一段密码足够快,以致拿走数据库的攻击者能在 GPU 上每秒尝试数十亿次。改用 bcrypt、scrypt 或 Argon2id。
- 忘记加盐,具有相同密码的两个用户绝不应产生相同的存储哈希。加盐(在哈希前为每个密码加上随机字节)可防止这一点并阻止彩虹表查找。
- 信任与文件来自同一处的哈希,攻破下载镜像的攻击者可同时换掉文件与其哈希。尽量从不同域获取哈希,或对哈希列表的 GPG 签名进行验证。
- 十六进制与 base64 混淆,同一哈希编码为 64 个十六进制字符或 44 个 base64 字符。比较不同编码总会失败。比较前请统一编码。
- 在安全代码中用
==比较,字符串比较在首个不同字符处短路,会泄露时序信息。在任何决定身份验证的代码中使用恒定时间的比较函数。 - 截短哈希以省空间,只取 SHA-256 的前 8 个字符,会把抗碰撞从天文数字降到微不足道。要么存储完整哈希,要么使用专为短输出设计的哈希(SipHash)。
- 用 CRC 做安全,CRC32 擅长发现意外损坏,但伪造起来毫不费力。任何人都可以追加字节,让 CRC 输出成任意选定值。
- 再哈希而不用 PBKDF,把 SHA-256 手动循环一万次是经典的自制密码哈希方案;它会泄露时序,且远比经过良好审计的 PBKDF2/bcrypt/Argon2 实现要慢。
- 把哈希与每次登录都相同的盐一起存放,读到哈希与盐的攻击者只需一次破解一个密码,但若你为所有用户复用一个全局盐,一张彩虹表就能把所有人都打破。每个用户使用一份新鲜的随机盐。
替代工具与库
浏览器哈希生成器是一次性哈希最快的路径。对于重复使用或脚本化,命令行与语言库接手。
| 工具 | 平台 | 优势 | 注意 |
|---|---|---|---|
| 网页哈希生成器 | 浏览器 | 即时、免安装、无上传 | 一次一个输入 |
sha256sum、md5sum | Linux | 可脚本、GNU coreutils | --check 读取 SHA256SUMS 文件 |
shasum -a 256 | macOS、BSD | 系统自带 | 与 Linux 上二进制名不同 |
Get-FileHash | Windows PowerShell | Windows 上一等公民 | 输出格式与 sha256sum 不同 |
openssl dgst -sha256 | 跨平台 | 如果你已经有 OpenSSL | 比专用工具慢 |
b3sum / BLAKE3 CLI | 跨平台 | 数 GB/s 吞吐 | 较新,不那么普及 |
Python hashlib | Python | 内置,涵盖所有主流算法 | 请使用字节输入 |
Node crypto | Node.js | 内置,API 与 Python 类似 | 大文件请用流式 |
Web Crypto subtle.digest | 浏览器 JS | 原生、快、无依赖 | 仅异步 API |
| HashiCorp Vault / KMS | 云 | 用于 HMAC 与签名的集中式密钥管理 | 厂商锁定 |
对于密码,语言生态请区别对待:使用 bcrypt、argon2-cffi、passlib 或你平台推荐的适配器,不要自己手写 SHA 循环。
隐私与哈希生成器
哈希生成器完全在你的浏览器中运行。你键入的文本会通过 Web Crypto SubtleCrypto 接口在内存中被哈希,你选择的任何文件都通过 FileReader API 流式传入,而不上传。没有记录哪些输入被哈希的日志,没有关于哪些算法流行的分析,也没人能重建你在验证什么。哈希本身常常是敏感材料的摘要,密码、内部文件、私钥,正是你绝不该粘进陌生人网页表单的那类数据。把工作放在客户端,可以把输入留在你的机器上,本该在那里。对于像生成校验和这样的日常任务,默认的隐私应当是:任何东西都不离开页面、不被存储、不被分享。
常见问题
MD5、SHA-1 和 SHA-256 有什么区别?
MD5 生成 128 位哈希(32 个十六进制字符),SHA-1 生成 160 位(40 个字符),SHA-256 生成 256 位(64 个字符)。MD5 和 SHA-1 被认为在密码学上已被攻破。SHA-256 目前是安全的,推荐用于完整性验证和安全。
可以反向破解哈希以找回原始数据吗?
不可以。哈希函数按设计是单向的。您无法从数学上将哈希反向为其输入。不过,常用密码可以在预计算表(彩虹表)中查找,这就是为什么在哈希前为密码加盐很重要。
什么是 HMAC?
HMAC(Hash-based Message Authentication Code)将哈希函数与密钥结合。它同时验证数据的完整性和真实性 · 证明它未被篡改且由知道密钥的人生成。
我的数据会发送到服务器吗?
不会。所有哈希都通过 Web Crypto API 在您的浏览器中运行。您的文本和文件从不离开您的设备。
Why should I never use MD5 or SHA-1 for password storage even with a salt?
Both algorithms are extremely fast, which is the opposite of what you want for passwords. An attacker with a stolen hash file can try billions of guesses per second on a GPU. Password-hashing functions like bcrypt, scrypt, and Argon2 are deliberately slow and memory-hard, which forces attackers to spend orders of magnitude more time per guess.
When should I use SHA-512 instead of SHA-256?
On 64-bit CPUs, SHA-512 is often slightly faster than SHA-256 because its inner state and word size are tuned to 64-bit operations. Use SHA-512 when you want a longer digest (128 hex characters) for collision resistance margin, or when you are already in a SHA-512 ecosystem (TLS 1.3 with certain cipher suites, some HMAC implementations).