Base64 编码在 Web 开发中无处不在——从直接在 HTML 中嵌入图片到通过 JSON API 传递二进制数据。尽管它很普遍,许多开发者仍将其视为黑盒,或错误地认为它能提供安全性。本文揭秘 Base64:它如何工作、何时使用,以及——关键——何时不能依赖它来保护数据。

什么是 Base64 编码?
Base64 是一种二进制到文本的编码方案,将二进制数据表示为 ASCII 字符串格式。它使用 64 个字符(A-Z、a-z、0-9、+、/)加上用于填充的 =。核心思想:每 3 个字节(24 位)的二进制数据被分成四个 6 位组,每个组映射到 Base64 字母表中的一个字符。
例如,字符串 Man 编码为 TWFu:
M→ 0x4D → 01001101a→ 0x61 → 01100001n→ 0x6E → 01101110- 合并:010011 010110 000101 101110 → T W F u
如果输入长度不是 3 的倍数,则添加填充(=)。两个字节变为三个字符加一个 =,一个字节变为两个字符加两个 =。
为什么使用 Base64?常见用例
Base64 解决了一个基本问题:许多传输机制(电子邮件、JSON、URL)是为文本设计的,而不是原始二进制。以下是最常见的场景:
在 HTML/CSS 中嵌入图片
无需单独的 HTTP 请求,你可以将图片作为数据 URI 内联:
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUA...">
这对于小型图标或精灵图很有用,减少请求次数胜过约 33% 的大小开销。
包含二进制数据的 API 负载
通过 JSON 发送文件或二进制数据时,必须对其进行编码。Base64 是标准方法:
{
"user": "alice",
"avatar": "data:image/jpeg;base64,/9j/4AAQSkZJRg..."
}
在数据库中存储二进制数据
许多数据库只有文本列,或者为了可移植性更倾向于文本。Base64 允许将任意字节存储在 VARCHAR 或 TEXT 字段中。
身份验证令牌
JWT(JSON Web Token)使用 Base64url(一种 URL 安全的变体)来编码头部、负载和签名。注意:负载未加密——任何拥有令牌的人都可以解码。
Base64 不是加密
这是最重要的结论:Base64 是编码,不是加密。它使用固定的、公开已知的映射。解码不需要密钥。任何看到 Base64 字符串的人都可以立即解码。
比较:
| 方面 | Base64 编码 | 加密(如 AES) |
|---|---|---|
| 目的 | 二进制到文本转换 | 机密性 |
| 可逆性 | 轻易可逆 | 仅凭密钥可逆 |
| 需要密钥 | 否 | 是 |
| 安全性 | 无 | 取决于算法/密钥 |
切勿使用 Base64 来“隐藏”敏感数据。这就像在显眼处写消息——任何人都能阅读。
安全注意事项
虽然 Base64 本身不提供安全性,但它可以成为安全管道的一部分:
- 与加密结合:先加密数据(例如 AES-256),然后对密文进行 Base64 编码以便传输。
- 避免泄露秘密:Base64 编码的令牌(如 JWT)绝不应完整记录。仅在必要时解码。
- 注意填充 oracle 攻击:如果实现自定义解密,确保不泄露填充错误。
性能和开销
Base64 使数据大小增加约 33%(3 字节 → 4 字符)。对于大型负载,这可能很显著。考虑替代方案:
- 二进制协议(例如 Protobuf、MessagePack)用于内部服务。
- 编码前压缩(例如 gzip 然后 Base64)用于大型数据块。
完整示例:端到端数据传输
让我们演练一个现实场景:一个 Web 应用允许用户上传头像,通过 JSON API 存储,然后显示。
步骤 1:在客户端编码图片(JavaScript)
const fileInput = document.getElementById('avatar');
const file = fileInput.files[0];
const reader = new FileReader();
reader.onload = function(e) {
const base64 = e.target.result.split(',')[1]; // 移除 data:... 前缀
// 发送到 API
fetch('/api/user/avatar', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ avatar: base64 })
});
};
reader.readAsDataURL(file);
步骤 2:在服务器端解码(Node.js 示例)
const express = require('express');
const app = express();
app.use(express.json({ limit: '5mb' }));
app.post('/api/user/avatar', (req, res) => {
const base64 = req.body.avatar;
const buffer = Buffer.from(base64, 'base64');
// 将 buffer 保存到磁盘或数据库
fs.writeFileSync('avatar.jpg', buffer);
res.status(200).send('OK');
});
步骤 3:显示图片(HTML)
<img src="data:image/jpeg;base64,/9j/4AAQSkZJRg...">
使用我们的 Base64 字符串转换器 亲自尝试——即时编码和解码任何文本或二进制数据。
常见陷阱
- 将 Base64 视为加密:切勿在未加密的情况下将密码或机密存储在 Base64 中。
- 忽略 URL 安全性:标准 Base64 使用
+和/,可能在 URL 中被误解。使用 Base64url(将+替换为-,/替换为_,去掉=)。 - 忘记填充:某些解码器容忍缺失,但为了正确性始终包含填充。
- 对大型文件过度使用:33% 的开销会累积。对于大型媒体,直接提供文件。
- 记录完整令牌:解码后的 JWT 会泄露用户声明。仅记录哈希或截断版本。
常见问题
使用 Base64 存储密码安全吗?
不安全。Base64 无需密钥即可逆。始终使用专用的密码哈希算法,如 bcrypt 或 Argon2。
没有填充也能解码 Base64 吗?
大多数现代解码器能优雅地处理缺失填充,但最佳实践是包含填充以严格合规。
Base64 和 Base64url 有什么区别?
Base64url 将 + 替换为 -,/ 替换为 _,并省略填充。它适用于 URL 和文件名。
Base64 会使文件大小增加多少?
编码数据本身正好增加 33%,加上换行符(如果使用 MIME 风格分块)的潜在开销。
应该在 Base64 编码之前还是之后压缩?
在之前压缩。Base64 编码会扩展数据,之后压缩效果较差。
结论
Base64 是 Web 开发中二进制到文本转换的实用工具。用于嵌入、API 负载和存储——但绝不能作为安全措施。当机密性重要时,始终与适当的加密配合使用。当需要快速编码或解码时,我们的 Base64 字符串转换器 随时可用。