
你可能见过像 SGVsbG8sIFdvcmxkIQ== 这样的字符串,并以为:“这看起来像是加密过的。” 你把它粘贴到解码器里,点击按钮,出来的是 Hello, World!——没有密钥,没有秘密。这是因为 Base64 不是加密。它是一种二进制到文本的编码方案,混淆两者可能导致严重的安全漏洞。
本文澄清这一误解,解释 Base64 的实际作用、底层工作原理,以及何时使用 Base64 与十六进制。我们还会通过一个完整的端到端示例让你看到它的实际应用。
编码 vs 加密:两件截然不同的事
我们一开始就讲清楚:
| 属性 | 编码(如 Base64、十六进制) | 加密(如 AES、RSA) |
|---|---|---|
| 目的 | 将二进制数据表示为文本以便安全传输 | 保护数据免受未授权访问 |
| 需要密钥? | 否 | 是 |
| 无需密钥即可还原? | 是,任何人都能解码 | 否,需要密钥 |
| 示例 | Man → Base64 → TWFu → 解码 → Man |
Man → AES → 0x3a7f... → 解密(密钥) → Man |
把编码想象成把一本书翻译成英文:任何懂英文的人都能读。加密是把书锁进保险箱:没有钥匙,谁也读不了。
常见误区:开发者有时会对密文进行 Base64 编码,以为这样“更安全”。这就像把保险箱的密码贴在门上——保险箱本身是安全的,但你亲手破坏了这种安全。
为什么需要二进制到文本编码?
计算机将所有数据存储为字节(0x00–0xFF)。其中许多字节是不可打印的——它们没有可见字符。例如:
0x00(NULL)——许多系统将其视为字符串结束0x0A(换行)——邮件服务器可能会断行0x0D(回车)——在不同操作系统间引发问题
如果你试图将原始二进制数据塞进纯文本通道(如电子邮件、URL 或 JSON),就会导致损坏、截断或解析错误。二进制到文本编码通过将任意字节映射到一组安全的可打印字符来解决这个问题。

Base64 工作原理:3 字节到 4 字符的魔法
编码表
Base64 使用 64 个可打印 ASCII 字符:
A–Z(索引 0–25)a–z(索引 26–51)0–9(索引 52–61)+(索引 62)和/(索引 63)=用于填充
为什么选这 64 个?因为它们在所有系统中都是安全的——没有控制字符,在大多数协议中没有特殊含义。
编码过程
- 取输入的 3 个字节(24 位)。
- 将这 24 位分成 4 组,每组 6 位。
- 将每个 6 位值(0–63)映射到表中的字符。
我们来编码 Man:
输入字节: M a n
ASCII: 77 97 110
二进制: 01001101 01100001 01101110
24 位流: 010011010110000101101110
6 位分组: 010011 010110 000101 101110
十进制: 19 22 5 46
表字符: T W F u
结果: "Man" → "TWFu"
3 个字节变成 4 个字符。数学原理:3 × 8 = 24 位;24 / 6 = 4 个字符。
填充:当数据不是 3 的倍数时
如果输入长度不是 3 的倍数,我们用零位填充,并用 = 标记填充:
- 1 字节(8 位):填充到 24 位,编码 → 2 字符 +
==(例如A→QQ==) - 2 字节(16 位):填充到 24 位,编码 → 3 字符 +
=(例如AB→QUI=) - 3 字节(24 位):无填充(例如
ABC→QUJD)
大小开销
Base64 增加约 33% 开销:对于 N 字节输入,输出长度为 ceil(N/3) × 4 字符。十六进制会使大小翻倍(每个字节变成 2 个十六进制字符),因此 Base64 更紧凑。
Base64 与十六进制:何时使用哪种?
| 特性 | Base64 | 十六进制 |
|---|---|---|
| 使用的字符 | 64(A–Z、a–z、0–9、+、/) | 16(0–9、A–F) |
| 开销 | ~33% | 100%(2 倍) |
| 人类可读? | 不太可读 | 一定程度上(十六进制数字熟悉) |
| 常见用途 | 电子邮件附件、数据 URI、API 负载 | 内存转储、颜色代码、调试 |
何时使用 Base64:
- 在 JSON/XML 中嵌入二进制数据
- 通过电子邮件发送二进制数据(MIME)
- HTML/CSS 中小图片的数据 URI
- 在纯文本数据库中存储二进制数据
何时使用十六进制:
- 调试和日志记录(更容易目视检查)
- 表示哈希摘要(例如 SHA-256)
- 大小不关键的底层协议
工作示例:编码和解码文件
我们来看一个真实场景:你有一个小图片文件(32 字节),想将其嵌入 JSON API 响应中。你将把它编码为 Base64。
步骤 1:获取原始字节
我们使用一个最小的 32 字节 PNG 头部(不是真实图片,只是原始字节):
89 50 4E 47 0D 0A 1A 0A 00 00 00 0D 49 48 44 52
00 00 00 01 00 00 00 01 08 02 00 00 00 90 77 53
步骤 2:用 Python 编码
import base64
raw_bytes = bytes([
0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52,
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
0x08, 0x02, 0x00, 0x00, 0x00, 0x90, 0x77, 0x53
])
encoded = base64.b64encode(raw_bytes).decode('ascii')
print(encoded)
# 输出: iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1VT
步骤 3:解码还原
decoded_bytes = base64.b64decode(encoded)
assert decoded_bytes == raw_bytes # True
你可以用我们的 Base64 字符串转换器 验证——粘贴编码后的字符串,查看解码后的十六进制。
常见陷阱
- 认为 Base64 是加密:它不是。任何人都可以用简单工具解码。绝不要用它保护敏感数据。
- 双重编码:对已编码的数据再次编码(例如对 Base64 字符串再做 Base64)浪费空间,且不增加安全性。
- 填充错误:缺少或多余的
=字符会导致解码失败。始终正确处理填充。 - URL 安全性:标准 Base64 使用
+和/,它们在 URL 中有特殊含义。对于 URL,请使用 Base64url(将+替换为-,/替换为_,省略填充)。 - 性能:Base64 编解码很快,但对于大文件(MB 级别),33% 的开销可能显著。考虑流式处理或压缩。
常见问题
Base64 对密码安全吗?
不安全。Base64 是编码,不是哈希或加密。密码应使用慢速加盐算法(如 bcrypt 或 Argon2)进行哈希。
如果我保密编码表,Base64 能用于加密吗?
通过隐藏实现安全不是真正的安全。Base64 算法是公开的,且逆向极其简单。任何人看到编码后的字符串都能解码,即使你使用自定义字符集。
为什么 Base64 使用填充(=)?
填充确保编码后的输出长度始终是 4 的倍数。某些解码器可以处理缺少填充的情况,但不能保证。
Base64 和 Base64url 有什么区别?
Base64url 使用 - 和 _ 代替 + 和 /,并省略填充。它适合在 URL 和文件名中使用,无需百分号编码。
如何将 Base64 转换为十六进制?
先将 Base64 字符串解码为字节,然后将这些字节编码为十六进制。例如,在 Python 中:base64.b64decode(s).hex()。我们的 Base64 字符串转换器 可以同时显示两种表示。
结论
Base64 是在纯文本通道上传输二进制数据的有用工具,但它不是加密。理解编码与加密的区别对于构建安全系统至关重要。当你需要机密性时,请使用带有密钥的适当加密算法。当你只需要安全地移动字节时,Base64(或十六进制)是你的朋友。
记住:如果你可以在没有密钥的情况下解码,那它就不是加密。