直接回答

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 后传输

为什么这么多人以为它是加密

三个原因叠在一起:

  1. 编码后的字符串看起来像乱码,直觉上就像被加密了
  2. 工具上写着「解码」按钮,而「解密」也差不多是这个动作
  3. 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 编解码,看它是不是不需要密钥就能还原。