← 返回文章列表

Base64 不是加密:编码与加密到底差在哪

编码加密入门

先把话挑明:Base64 真不是加密

你大概见过这种想法:把密码用 Base64 处理一下,变成一串看不懂的字符,应该就安全了吧?并不是。Base64 只是一种编码,拿到这串字符,任何人写一行代码就能还原出原样。它和加密是两回事。

编码、加密、哈希,到底差在哪

这三个词老被混着用,但它们解决的问题不一样:

  • 编码:为了让数据能正常传、能正常存。它完全可逆,而且不需要密钥,谁拿到都能还原。
  • 加密:为了不让不该看的人看到。没有密钥就解不开。
  • 哈希:单向的,用来确认数据没被改过,或者存口令的摘要。

Base64 干的事很单纯:把任意二进制,映射成 64 个可打印字符(A-Z、a-z、0-9、+、/)。这样数据就能塞进只认文本的通道,比如邮件、URL、JSON。

怎么一眼认出 Base64

  1. 字符只会出现在 A-Z、a-z、0-9、+、/ 这个范围;
  2. 长度是 4 的倍数,因为每 3 个字节会变成 4 个字符,体积大约涨 33%;
  3. 结尾常有 = 或 == 做填充。

到底该用哪个

在文本协议里带二进制(图片内联、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 编解码、对称加密、哈希计算