密码与加密基础篇(1):别再说 MD5 加密了:编码、摘要、加密到底有什么区别?

📅 2026/6/22 2:06:46
密码与加密基础篇(1):别再说 MD5 加密了:编码、摘要、加密到底有什么区别?
在项目里我们经常会听到一些说法密码用 MD5 加密一下 Token 做个 Base64 加密 接口参数用 SHA 加密 JWT 是加密后的用户信息这些话在日常沟通里很常见但严格来说很多表述并不准确。尤其是这句MD5 加密一下。严格来说MD5 不是加密而是摘要也可以叫哈希。这个概念如果不分清楚后面理解密码存储、Token 安全、接口签名、AES、RSA、HTTPS、Android Keystore 都会变得很混乱。这一篇就先把最基础的几个概念讲清楚编码 摘要 / 哈希 加密 签名 传输加密 Token 格式 密钥保护一、为什么要先讲这些基础概念因为很多安全问题表面上是代码问题本质上是概念混淆。比如把 Base64 当加密 把 MD5 当加密 把 JWT 当加密 把 HTTPS 和本地加密混在一起 把 Android Keystore 和 APK 签名 keystore 混在一起这些概念一旦混了设计就容易出问题。比如 Token 本地存储如果你以为MD5(token) 就是加密保存 token那就错了。因为 MD5 之后Token 根本拿不回来了。再比如密码存储如果你以为密码加密存数据库登录时再解密出来比较这也不对。密码不应该能被后端解密还原正确做法是做密码哈希然后登录时重新计算并比较。所以这篇文章先不讲复杂数学原理只讲工程里最容易混的几个概念。二、先给结论这些东西分别是什么可以先看这张表。名称本质能不能还原常见用途Base64编码可以还原二进制转字符串MD5 / SHA摘要 / 哈希不能还原文件校验、密码哈希、数据摘要HMAC带密钥的消息认证码不能还原接口签名、防篡改AES对称加密可以解密本地数据加密、Token 加密存储RSA非对称加密 / 签名可以解密 / 可验签加密 AES key、签名验签HTTPS传输层加密对业务透明保护网络传输JWTToken 格式默认可解析登录态、身份声明Android Keystore密钥保护系统不是加密算法保护 AES / RSA 密钥你先记一句话Base64 是编码MD5/SHA 是摘要AES/RSA 才是加密相关算法HTTPS 是传输安全JWT 是 Token 格式Keystore 是密钥保护系统。三、Base64编码不是加密Base64 经常被误认为是加密。比如hello经过 Base64 之后变成aGVsbG8看起来像是“变乱了”但它不是加密。因为任何人拿到这个字符串都可以直接还原aGVsbG8 → helloBase64 的作用是把二进制数据转成文本字符串方便传输和存储。比如图片、密文、IV、签名结果有时候都是二进制数据不方便直接放到 JSON 里这时就会先 Base64。例如{ iv: Base64后的IV, cipherText: Base64后的密文 }这里 Base64 只是编码。真正加密的是 AES-GCM。所以不要说Base64 加密准确说法应该是Base64 编码四、MD5摘要不是加密MD5 也经常被说成“加密”。比如123456MD5 后得到e10adc3949ba59abbe56e057f20f883e看起来像密文但它不是加密。因为加密的特点是明文 → 密文 → 可以解密回明文而 MD5 的特点是明文 → 摘要值不能从摘要值反推出原文。所以 MD5 是摘要不是加密。准确说法是对数据做 MD5 摘要而不是对数据做 MD5 加密五、摘要有什么特点摘要 / 哈希算法有几个特点。1. 固定长度输出无论输入多长输出长度通常固定。比如 MD5 输出 32 位十六进制字符串。hello → 5d41402abc4b2a76b9719d911017c592输入是一句话、一篇文章、一个文件最后 MD5 输出长度都一样。2. 不可逆摘要不能解密。123456 → e10adc3949ba59abbe56e057f20f883e不能通过这个摘要值直接解密出123456。当然常见密码可能被猜出来。比如攻击者提前准备一张表123456 → e10adc3949ba59abbe56e057f20f883e 111111 → 96e79218965eb72c92a549dd5a330112 password → 5f4dcc3b5aa765d61d8327deb882cf99这不是“解密”而是“猜中”。3. 相同输入得到相同输出MD5(123456)每次结果都一样。这也是为什么 MD5 可以用来校验文件有没有变化。比如下载文件时服务端给一个 MD5 值。客户端下载完成后也算一次 MD5。服务端 MD5 abc 本地文件 MD5 abc如果一致说明文件大概率没有损坏。4. 输入稍微变化输出差异很大比如hello hello1这两个输入很接近但 MD5 结果会完全不同。这也是摘要算法的特性。六、MD5 常见用在哪里MD5 不是完全不能用而是要看场景。1. 文件校验比如MD5(file)用来判断文件有没有损坏、有没有变化。这种场景下MD5 还能看到。2. 缓存 key比如 URL 很长https://example.com/image/xxxx?a1b2可以做cacheKey MD5(url)用固定长度字符串做缓存文件名。这种属于工程便利不是安全加密。3. 接口签名老项目常见一些老项目会这样sign MD5(param1 param2 secret)这种做法以前很常见但更规范的方案一般是 HMAC-SHA256。4. 密码存储老项目常见但不推荐比如password MD5(123456)或者password MD5(password salt)这在老项目里很多但现在不推荐作为密码存储方案。因为 MD5 太快了攻击者可以快速暴力猜测。现代密码存储更推荐bcrypt Argon2id PBKDF2这些属于专门的密码哈希算法会故意变慢让攻击者批量猜密码的成本变高。七、SHA 和 MD5 一样也是摘要SHA 系列比如SHA-1 SHA-256 SHA-512本质也是摘要算法。它们也不是加密。比如SHA-256(hello)得到的是一个摘要值不能解密回hello。所以不要说SHA 加密准确说法是SHA 摘要不过要注意虽然 SHA-256 比 MD5 更安全但它本质上仍然是快速哈希。所以如果是存密码不应该简单写password SHA-256(password)密码存储仍然应该使用bcrypt / Argon2id / PBKDF2八、HMAC带密钥的摘要除了 MD5、SHA还有一个接口安全里常见的东西HMAC比如HMAC-SHA256它可以理解为带密钥的消息认证码普通 SHA 是hash(data)HMAC 是hmac(data, secret)它多了一个 secret。所以 HMAC 常用于接口签名。比如sign HMAC-SHA256(requestBody timestamp nonce, secret)后端也用同样的 secret 计算一次如果结果一致说明1. 请求内容没有被篡改 2. 请求方知道这个 secretHMAC 不是加密因为它不能还原原文。它的作用是防篡改 做身份校验 做接口签名九、AES对称加密AES 才是加密算法。它的特点是同一个 key 用来加密 同一个 key 用来解密所以叫对称加密。流程是明文 ↓ AES 加密 密文 ↓ AES 解密 明文在移动端安全里AES 很常见。比如 Token 本地存储Token 明文 ↓ AES-GCM 加密 Token 密文 ↓ 存到 DataStore / MMKV后面要请求接口时Token 密文 ↓ AES-GCM 解密 Token 明文 ↓ 加到 Authorization Header所以 Token 不能用 MD5因为 Token 后续还要还原出来使用。Token 应该用 AES 这类可逆加密算法。十、AES-GCM更适合本地敏感数据加密AES 也有不同模式。不要随便用AES/ECB/PKCS5PaddingECB 模式不推荐。更推荐AES/GCM/NoPaddingAES-GCM 的特点是加密数据 校验数据完整性也就是说它不仅能让别人看不到明文还能发现密文是否被篡改。移动端 Token 本地存储就适合AES-GCM Android Keystore这里的关系是AES-GCM加密 Token Android Keystore保护 AES key DataStore / MMKV保存 Token 密文十一、RSA非对称加密RSA 和 AES 不一样。RSA 有一对 key公钥 public key 私钥 private key常见两种用法公钥加密私钥解密 私钥签名公钥验签比如客户端要给后端发一个 AES keyAES key ↓ RSA 公钥加密 encryptedAesKey后端收到后encryptedAesKey ↓ RSA 私钥解密 AES key这种就是典型的RSA 负责保护 AES key AES 负责加密真正的数据十二、为什么不直接用 RSA 加密所有数据因为 RSA 不适合加密大量数据。它的问题是慢 加密数据长度有限 不适合大请求体 不适合文件加密所以工程里经常是AES 加密业务数据 RSA 加密 AES key这叫混合加密。比如一次接口请求App 生成临时 AES key ↓ AES-GCM 加密请求体 ↓ RSA 公钥加密 AES key ↓ 发送 encryptedKey iv cipherText后端RSA 私钥解出 AES key ↓ AES-GCM 解密请求体 ↓ 拿到业务明文所以记住AES 加密数据RSA 加密 AES 密钥。十三、HTTPS传输层安全HTTPS 不是某一个简单算法而是一整套传输安全协议体系。它解决的是App 到服务器之间的数据传输安全包括防窃听 防篡改 身份校验 密钥协商普通 App 登录时通常就是用户输入密码 ↓ HTTPS/TLS 加密传输 ↓ 后端收到密码所以客户端通常不需要自己先 MD5也不一定需要自己再 RSA 加密密码。因为 HTTPS 已经负责传输层加密。但注意HTTPS 只保护传输过程。它不保护本地明文 Token 本地日志泄漏 后端数据库明文密码 Crash 上报带出的敏感字段所以 HTTPS 不是万能的。十四、JWTToken 格式不是加密JWT 很容易被误解为加密。JWT 一般长这样header.payload.signature它的 payload 默认只是 Base64Url 编码不是加密。也就是说别人拿到 JWT通常可以解析出 payload 内容。所以 JWT 里不要放敏感信息比如密码 身份证 银行卡 手机号完整信息 隐私数据JWT 适合放userId tenantId role exp iat jtiJWT 的 signature 主要作用是防篡改 证明这个 Token 是由可信方签发的不是防读取。所以不要说JWT 是加密后的用户信息更准确的是JWT 是带签名的 Token 格式。十五、Android Keystore密钥保护系统不是加密算法Android Keystore 也容易被误解。它不是 AES也不是 RSA。它是 Android 系统提供的密钥保护能力。它的作用是生成密钥 保存密钥 限制密钥用途 让密钥更难被导出比如 Token 本地加密Android Keystore 生成 AES key ↓ AES-GCM 用这个 key 加密 Token ↓ Token 密文存到 DataStore / MMKV所以不是Token 存进 Keystore而是AES key 进 Keystore Token 密文存本地这一点非常关键。十六、密码、Token、接口签名分别应该用什么1. 密码密码不需要还原。后端只需要验证。所以密码应该用bcrypt / Argon2id / PBKDF2不推荐MD5(password) SHA-256(password)密码的核心是不可逆 慢 带 salt 抗暴力猜测2. TokenToken 后续还要拿出来请求接口。所以 Token 本地存储应该用AES-GCM 加密 Android Keystore 保护 AES key不能用MD5(token)因为 MD5 之后拿不回原始 Token。3. 接口签名接口签名一般用于防篡改。可以使用HMAC-SHA256比如sign HMAC-SHA256(body timestamp nonce, secret)它不是加密而是认证和防篡改。4. 业务层接口加密如果业务要求在 HTTPS 之外再加密请求体可以使用AES-GCM 加密请求体 RSA-OAEP 加密 AES key也就是混合加密。十七、几个常见错误说法错误说法 1Base64 加密错误。Base64 是编码可以还原。正确说法Base64 编码错误说法 2MD5 加密错误。MD5 是摘要不能解密。正确说法MD5 摘要错误说法 3SHA 加密错误。SHA 是摘要。正确说法SHA 哈希 / SHA 摘要错误说法 4JWT 是加密的不准确。JWT 默认只是 Base64Url 编码 签名。正确说法JWT 是带签名的 Token 格式不是加密容器。错误说法 5用了 DataStoreToken 就安全了错误。DataStore 只是存储容器。正确说法Token 需要先 AES-GCM 加密再存到 DataStore。错误说法 6Keystore 用来存 Token不准确。正确说法Keystore 用来保护 AES keyToken 是加密后存本地。十八、一张图串起来可以用这张图总结编码 Base64 ↓ 解决二进制转字符串问题不解决安全问题 摘要 MD5 / SHA ↓ 生成不可逆摘要适合校验不适合还原 密码存储 bcrypt / Argon2id / PBKDF2 ↓ 专门用于密码哈希故意变慢 加密 AES ↓ 适合加密数据比如 Token、本地文件、请求体 非对称加密 RSA ↓ 适合加密 AES key、签名验签 传输安全 HTTPS ↓ 保护 App 到服务器之间的数据传输 Token 格式 JWT ↓ 带签名的 Token 格式不是默认加密 密钥保护 Android Keystore ↓ 保护 AES / RSA 密钥不直接存业务数据十九、总结这一篇最重要的目的是把几个概念拉正。你只要记住这些话Base64 是编码不是加密。 MD5 / SHA 是摘要不是加密。 HMAC 是带密钥的消息认证码常用于接口签名。 AES 是对称加密适合加密业务数据和本地 Token。 RSA 是非对称加密适合加密 AES key 和签名验签。 HTTPS 是传输层安全保护网络传输过程。 JWT 是 Token 格式默认不是加密。 Android Keystore 是密钥保护系统不是加密算法。如果再压缩成一句话编码解决格式问题摘要解决校验问题加密解决保密问题签名解决防篡改和身份问题HTTPS 解决传输安全Keystore 解决密钥保护。这句话理解了后面再看密码存储、Token 安全、AES-GCM、RSA 混合加密、Android Keystore就不会乱了。