MD5 vs SHA1 vs SHA256:应该使用哪种哈希?(附实时示例)
发布: (2026年3月20日 GMT+8 03:17)
6 分钟阅读
原文: Dev.to
Source: Dev.to
选择合适的算法
| 用例 | 推荐算法 | 备注 |
|---|---|---|
| 密码存储 | bcrypt / Argon2 | 切勿直接使用 MD5/SHA‑1/SHA‑256 |
| 数字签名 | SHA‑256 | 符合 NIST 标准 |
| 文件完整性 | SHA‑256 (or MD5) | MD5 仅在非安全场景下可接受 |
| JWT (HS256) | SHA‑256 | 标准选择 |
| Git 提交 | SHA‑1 → SHA‑256 | 正在迁移中 |
| TLS 证书 | SHA‑256 | SHA‑1 证书已被拒绝 |
| HMAC | SHA‑256 or SHA‑512 | 均安全 |
加密哈希的工作原理
哈希函数接受任意输入并产生固定长度的输出。
import hashlib
text = "Hello, World!"
md5 = hashlib.md5(text.encode()).hexdigest() # 32 hex chars
sha1 = hashlib.sha1(text.encode()).hexdigest() # 40 hex chars
sha256 = hashlib.sha256(text.encode()).hexdigest() # 64 hex chars
sha512 = hashlib.sha512(text.encode()).hexdigest() # 128 hex chars
print(sha256)
# 315f5bdb76d078c43b8ac0064e4a0164612b1fce77c869345bfc94c75894edd3
关键特性
- 确定性 – 相同的输入始终产生相同的输出。
- 单向性 – 逆向计算哈希值在实际中不可行。
- 雪崩效应 – 单个位的变化会导致输出完全不同。
- 抗碰撞性 – 难以找到两个不同的输入拥有相同的哈希值。
MD5
产生一个 128 位(32 十六进制字符)的哈希。
- 状态: 密码学已被破坏。仅用于非安全校验和。
- 历史攻击:
- 2004 年 – 已展示碰撞攻击。
- 2008 年 – 使用 MD5 碰撞创建了伪造的 CA 证书。
- 2012 年 – Flame 恶意软件伪造了 Windows Update 签名。
// Node.js
const crypto = require('crypto');
const hash = crypto.createHash('md5').update('Hello').digest('hex');
console.log(hash); // 8b1a9953c4611296a827abf8c47804d7
安全使用
- 非安全的文件去重。
- 在可接受碰撞的情况下缓存键。
- 兼容旧系统。
不安全的使用
- 密码哈希。
- 数字签名。
- SSL/TLS 证书。
- 任何安全关键的上下文。
SHA‑1
产生一个 160 位(40 个十六进制字符)的哈希。
- 状态: 已不建议在新代码中使用;已可实现碰撞。
- 显著攻击: 2017 年 “SHAttered” 碰撞展示了两个不同的 PDF 具有相同的 SHA‑1 哈希。
# Two different PDFs with the same SHA‑1 hash
sha1sum shattered-1.pdf shattered-2.pdf
# 38762cf7f55934b34d179ae6a4c80cadccbb7f0a shattered-1.pdf
# 38762cf7f55934b34d179ae6a4c80cadccbb7f0a shattered-2.pdf
- Git 仍然使用 SHA‑1 作为提交 ID(正在迁移到 SHA‑256)。
- 浏览器会拒绝使用 SHA‑1 签名的 TLS 证书。
建议: 在新应用中避免使用 SHA‑1;在可能的情况下迁移已有的使用场景。
SHA‑256(SHA‑2 系列的一部分)
生成 256 位(64 个十六进制字符)的哈希。
- 状态: 当前标准;被广泛信任。
- 常见用途:
- 比特币区块链。
- TLS 1.3。
- JWT 签名(HS256、RS256、ES256)。
- 代码签名证书。
- 密码管理器。
// Node.js
const crypto = require('crypto');
const hash = crypto.createHash('sha256').update('Hello').digest('hex');
console.log(hash); // 185f8db32921bd46d35cc3c66b9a7b8f3a2bc37f9f0e87c
// Browser (Web Crypto API)
async function sha256(text) {
const data = new TextEncoder().encode(text);
const buf = await crypto.subtle.digest('SHA-256', data);
return Array.from(new Uint8Array(buf))
.map(b => b.toString(16).padStart(2, '0'))
.join('');
}
sha256('Hello').then(console.log);
import hashlib
print(hashlib.sha256(b'Hello').hexdigest())
HMAC(基于哈希的消息认证码)
将密钥与哈希函数结合,用于对消息进行认证。
import hmac, hashlib
secret = b'my-secret-key'
message = b'user_id=123&amount=50'
sig = hmac.new(secret, message, hashlib.sha256).hexdigest()
print(sig) # Verify that the message wasn't tampered with
常见用法
- JWT 签名(HS256 = HMAC‑SHA256)。
- Webhook 负载校验(GitHub、Stripe)。
- API 请求签名(AWS Signature V4)。
密码哈希:为什么直接使用 SHA‑256 是错误的
# WRONG — never do this
import hashlib
password_hash = hashlib.sha256(password.encode()).hexdigest()
- 太快 – 攻击者每秒可以尝试数十亿次猜测。
- 没有盐 – 易受彩虹表攻击。
- 确定性 – 相同的密码产生相同的哈希,泄露重复信息。
正确做法
# RIGHT — use bcrypt (or Argon2/scrypt)
import bcrypt
hashed = bcrypt.hashpw(password.encode(), bcrypt.gensalt())
合适的密码哈希器的特性
- 慢 – 可配置的成本因子。
- 加盐 – 每个密码唯一。
- 内存硬 – Argon2 和 scrypt 能抵御 GPU/ASIC 攻击。
快速语言示例
Node.js(crypto 模块)
const { createHash, createHmac } = require('crypto');
createHash('sha256').update('text').digest('hex');
createHmac('sha256', 'key').update('text').digest('hex');
Python
import hashlib, hmac
hashlib.sha256(b'text').hexdigest()
hmac.new(b'key', b'text', hashlib.sha256).hexdigest()
Go
import "crypto/sha256"
import "fmt"
func main() {
h := sha256.Sum256([]byte("text"))
fmt.Printf("%x\n", h)
}
Shell
echo -n "text" | sha256sum
echo -n "text" | md5sum
API 示例:编程哈希
curl -X POST https://api.aiforeverthing.com/api/hash/generate \
-H "Content-Type: application/json" \
-d '{"text": "hello world", "algorithm": "sha256"}'
摘要速查表
| 算法 | 典型使用场景 | 安全立场 |
|---|---|---|
| MD5 | 非安全校验和、旧版去重 | 快速,已破‑ 仅用于非安全 |
| SHA‑1 | 旧系统(例如老 Git 仓库) | 已弃用 – 在新代码中避免使用 |
| SHA‑256 | 通用哈希、签名、JWT、TLS | 当前标准 – 默认选择 |
| SHA‑512 | 最高安全性,通常在 64 位 CPU 上更快 | 强大 – 在需要额外安全余量时使用 |
| bcrypt / Argon2 / scrypt | 密码存储 | 始终 使用专用的密码哈希器 |
| HMAC‑SHA256(或 SHA‑512) | 消息认证、API 签名、JWT | 在已认证的上下文中 安全 |
选择符合您应用安全需求的算法;切勿在任何安全关键的场景中使用已破的哈希(MD5、SHA‑1)。