先把话挑明:Base64 真不是加密
你大概见过这种想法:把密码用 Base64 处理一下,变成一串看不懂的字符,应该就安全了吧?并不是。Base64 只是一种编码,拿到这串字符,任何人写一行代码就能还原出原样。它和加密是两回事。
编码、加密、哈希,到底差在哪
这三个词老被混着用,但它们解决的问题不一样:
- 编码:为了让数据能正常传、能正常存。它完全可逆,而且不需要密钥,谁拿到都能还原。
- 加密:为了不让不该看的人看到。没有密钥就解不开。
- 哈希:单向的,用来确认数据没被改过,或者存口令的摘要。
Base64 干的事很单纯:把任意二进制,映射成 64 个可打印字符(A-Z、a-z、0-9、+、/)。这样数据就能塞进只认文本的通道,比如邮件、URL、JSON。
怎么一眼认出 Base64
- 字符只会出现在 A-Z、a-z、0-9、+、/ 这个范围;
- 长度是 4 的倍数,因为每 3 个字节会变成 4 个字符,体积大约涨 33%;
- 结尾常有
=或==做填充。
到底该用哪个
在文本协议里带二进制(图片内联、JWT、附件),用 Base64;需要保密,用 AES 这类对称加密加随机密钥;要确认“没被改过”,用 SHA-256 这类哈希。三者经常一起出现,但谁也替不了谁。
同一件事,该用哪个:一张表看完
| 场景 | 该用什么 | 为什么 |
|---|---|---|
| 在 JSON / URL / 邮件里携带二进制 | Base64 | 可逆、不需要密钥,只解决“怎么传” |
| 只有自己人能读 | AES-GCM 等对称加密 | 没有密钥解不开,还能发现被篡改 |
| 校验文件是否被改动 | SHA-256 等哈希 | 单向不可逆,改一位就得到完全不同的摘要 |
| 保存用户口令 | bcrypt / Argon2 | 自带盐值和慢哈希,暴力破解的成本会高很多 |
代码示例
// 浏览器:中文必须先转 UTF-8 字节,否则 btoa 会抛错
const encoded = btoa(String.fromCharCode(...new TextEncoder().encode('中文文本')));
const decoded = new TextDecoder().decode(
Uint8Array.from(atob(encoded), c => c.charCodeAt(0))
);
// Node.js:原生支持 UTF-8,最省心
const b64 = Buffer.from('中文文本', 'utf8').toString('base64');
const back = Buffer.from(b64, 'base64').toString('utf8');
三个容易踩的坑
- 把 Base64 当加密:想“藏”密码,但解码只要一行代码;
- 直接拿 btoa 处理中文:btoa 只认 Latin-1,中文直接抛异常,得先转成字节;
- 把大文件转成 Base64 塞进页面:体积涨约 33%,还拖慢首屏,超过几 KB 就别内联了。
顺手答两个常见问题
JWT 为什么用 Base64Url?标准 Base64 里的 +、/ 在 URL 里会被转义或截断,所以 JWT 把 + 换成 -、/ 换成 _,还去掉了 = 填充。Base64 能压缩数据吗?不能,它反而让数据变大,只是让数据变得“能打印”而已。
动手试试:Base64 编解码、对称加密、哈希计算