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‑256SHA‑1 证书已被拒绝
HMACSHA‑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)。

0 浏览
Back to Blog

相关文章

阅读更多 »

下一个排列

问题描述:任务是计算给定数字数组的下一个排列。排列是相同元素的重新排列,而下一个…