直接回答
Base64 不是加密,是编码。
它没有密钥,任何人都能还原。你把一段文字 Base64 之后,保密性一点都没有增加,只是换了个样子。
编码和加密的区别
这两个词经常被混用,但做的是完全不同的事:
| 编码(Encoding) | 加密(Encryption) | |
|---|---|---|
| 目的 | 让数据能被正确传输/存储 | 让数据不被别人看懂 |
| 密钥 | 没有 | 有 |
| 可逆性 | 任何人都能还原 | 只有持密钥的人能还原 |
| 例子 | Base64、URL 编码、UTF-8 | AES、RSA |
一句话:编码解决「放得进去」,加密解决「看得懂」。
Base64 真正解决什么问题
它要解决的是一个很具体的工程问题:有些通道只能传输文本,但你的数据是二进制的。
历史来源是电子邮件。早期的邮件协议只保证传输 ASCII 文本,直接塞二进制字节会被中间环节改坏。于是有人设计了 Base64:把每 3 个字节(24 位)拆成 4 个 6 位,每个 6 位映射到一个可打印字符。
原始 3 字节: 01001101 01100001 01101110 ("Man")
拆成 6 位: 010011 010110 000101 101110
查表映射: T W F u
结果: "TWFu"
代价是体积膨胀约 33%(3 字节变 4 字符)。换来的是纯 ASCII 输出,经过任何文本通道都不会损坏。
所以你在这些地方会看到它:
- 邮件附件(MIME 编码)
- Data URI(把图片直接嵌进 HTML 或 CSS)
- JSON 里传二进制数据(JSON 本身不支持二进制)
- HTTP Basic 认证的凭据
- 有些 API 要求把签名或密钥 Base64 后传输
为什么这么多人以为它是加密
三个原因叠在一起:
- 编码后的字符串看起来像乱码,直觉上就像被加密了
- 工具上写着「解码」按钮,而「解密」也差不多是这个动作
- Base64 经常和加密算法一起出现(比如 AES 加密后的密文通常再 Base64 一下才能放进文本),容易把两步混成一步
但你把任意一段 Base64 贴进 Base64 编解码,它立刻就能还原——不需要任何密钥。这就是它和加密最本质的分界。
关键:常见误用
下面这些做法都等于没做保护:
① 把密码 Base64 后传输
js// 这是明文,不是加密
const safe = btoa(password)
任何能抓包的人,一行代码就还原了。
② 把敏感参数 Base64 后放进 URL
js// 看起来像令牌,其实谁都能解
/api/data?token=${btoa(userId + ':' + role)}
甚至有人以为这样就防住了用户改参数——完全防不住。想防篡改要用签名(HMAC),不是编码。
③ 在 localStorage 里存 Base64 的凭据
同源下任何 XSS 都能读到并解码。
那真正需要保密时该用什么
分两个层面:
传输层:用 HTTPS。这是最重要的一条——只要上了 HTTPS,链路上的内容本来就是加密的,不需要你再套一层。
内容层:真的需要对数据本身加密(比如存在客户端、或者要给第三方传),用正经的加密算法,比如 AES。可以先用 AES 加解密 试试 AES 的行为,注意密钥管理才是难点——密钥泄露了算法再强也没用。
两个实用细节
URL 安全变体
标准 Base64 的字符表里有 + 和 /,这两个字符放在 URL 里有特殊含义,会出问题。所以有个 URL-safe 变体,把它们换成 - 和 _。需要往 URL 或文件名里放 Base64 时要用这个变体。
末尾的 = 是什么
那是填充符。Base64 按 3 字节一组处理,不够的用 = 补上。有些实现会去掉 = 让字符串更短,解码时再补回来。遇到「Base64 解不开」的情况,先看看是不是填充符被去掉了。
小结
- Base64 是编码,用于让二进制数据通过文本通道,不是加密
- 没有密钥,任何人都能还原
- 把密码、令牌、敏感参数 Base64 一下再传输,等于明文
- 传输安全靠 HTTPS,数据加密靠 AES 这类真正的加密算法
想自己验证一遍——把任意一段 Base64 粘到 Base64 编解码,看它是不是不需要密钥就能还原。