什么是 Base64 编码,何时使用它

· 9 分钟阅读

如果你跟 API、邮件系统或网页开发打交道,你就遇到过 Base64,只是可能没认出来。那些在邮件附件开头、CSS 中的 data: URL,或者 JWT 中间段里看上去乱七八糟的长串字母数字?那就是 Base64。它是互联网管道里最古老也最默默承重的一段之一,几乎你用的每一款软件都在某处依赖它。

Base64 简史

Base64 属于一族叫做「radix-64」或「可打印编码」的方案,它们的工作是用文本系统保证原样通过的那套小字母表,来表示任意字节。最早被广泛使用的成员是 uuencode,由 Mary Ann Horton 在 UC Berkeley 大约 1980 年写出,用于在那个 7 位 ASCII 以上一切都会被破坏的年代,通过 Usenet 和邮件传输二进制文件。

Base64 字母表本身最早在 RFC 989(1987)里为隐私增强邮件(PEM)标准化,后者是签名和加密邮件的早期尝试。PEM 死了,但它的编码方案活了下来,被 RFC 1421(1993)以及随后的 MIME 规范(1993 年的 RFC 1521 和 1522,1996 年修订为 RFC 2045 到 2049)正式收编。MIME 把 Base64 定为附加二进制文件到邮件的默认方式,从这里出发,这种编码扩散到了互联网上几乎所有纯文本传输通道。

2006 年,IETF 把分散的 Base64 定义整合进 RFC 4648,在同一份文档里定义了 Base64、Base32 和 Base16。RFC 4648 还在第 5 节定义了 URL 安全变种,把两个对 URL 不友好的字符(+/)换成 -_。JSON Web Token(RFC 7519,2015)统一使用去掉填充的 URL 安全 Base64。今天,每一份邮件附件、每一张 PEM 编码证书、每一个 data: URL、每一枚 JWT、每一个 multipart 上传边界,都依赖 Base64。

Base64 如何工作:数学

Base64 取三个输入字节(24 位),用一个 64 符号的字母表把它们重写为四个输出字符(每个 6 位)。映射是固定的:

索引范围字符
0-25A-Z
26-51a-z
52-610-9
62+(标准)或 -(URL 安全)
63/(标准)或 _(URL 安全)

所以 Hello 变成:

输出总是 4 个字符的倍数。如果输入长度模 3 为 1,你得到两个 = 填充字符;为 2 则一个;为 0 则没有。填充有时会被去掉(特别是 JWT 和 URL 片段),解码器需要容忍这种情况。

33 % 的体积开销正来自这一 3 比 4 的扩张:每 3 字节的输入变 4 个字符的输出,多三分之一。除非换字母表,否则无法缩小(Base85 / Ascii85 用 85 个可打印字符把扩张降到 25 %,代价是更复杂的编码器)。

常见用例

邮件附件。SMTP,这个承载 95 % 服务器间邮件的协议,1982 年设计时(RFC 821)是为 7 位 ASCII 设计的。你发的每一份二进制附件(图片、PDF、ZIP)都在传输前被你的邮件客户端编为 Base64,再被收件人的客户端解开。邮件里的 MIME 头告诉收件人哪些部分是 Base64,哪些是纯文本。

HTML 与 CSS 中的 data URL。形如 data:image/png;base64,iVBORw0KGgo... 的 URL 把一个二进制文件直接嵌进文档里。对 1-2 KB 以下的小图标有用,这时节省一次 HTTP 请求的收益超过 33 % 的开销和失去缓存的代价。

API 负载。当 JSON 或 XML API 需要接收二进制值(上传文件、签名、头像)时,标准做法是把字节编为 Base64,作为字符串字段发送。接收方在服务端解码。OpenAI 的图像输入是这样工作的,Stripe 接收文件上传也是,大多数云函数接收二进制输入还是。

HTTP Basic 认证。Authorization: Basic <token> 头携带一对以 Base64 编码的 username:password(RFC 7617)。这是编码,不是加密:任何看到头部的人都看到了密码。Basic Auth 因此要求 HTTPS。

证书与密钥。PEM 文件(-----BEGIN CERTIFICATE----- ... -----END CERTIFICATE-----)把一团 DER 编码的 ASN.1 字节用 Base64 包起来。每一份 TLS 证书、每一个 SSH 密钥文件、每一份代码签名证书,都是 PEM 信封内的 Base64。

JWT 令牌。JWT 是用点分隔的三段 URL 安全 Base64:<header>.<payload>.<signature>。Base64 编码让 JWT 能安全地放进头部、URL 和 cookie 中传输。

如何编码与解码

  1. 选择编码或解码:选择转换方向。
  2. 粘贴文本或上传文件:直接输入文本或拖放文件(浏览器侧编码最多 5 MB)。
  3. 选择变种:邮件和证书用标准 Base64,JWT 和 URL 片段用 URL 安全。工具默认是标准。
  4. 复制结果:输出实时更新。复制到剪贴板,或者长输出用下载按钮。

Base64 的变种

针对特定场景存在若干类 Base64 的编码:

变种差异使用场合
标准(RFC 4648 §4)A-Z、a-z、0-9、+、/、= 填充邮件(MIME)、PEM、通用二进制转文本
URL 安全(RFC 4648 §5)+ 变 -,/ 变 _JWT、URL 片段、文件名
MIME(RFC 2045)每 76 字符一次换行邮件正文、邮件头(配合 =?utf-8?B?...?=)
crypt(3) / htpasswd不同字母表(./0-9A-Za-z)老式 Unix 密码哈希(基于 DES)
无填充 Base64UrlURL 安全无尾部 =JWT(按 RFC 7515)
Base32(RFC 4648 §6)32 字符字母表,不区分大小写TOTP 密钥、Onion 地址
Base5858 字符字母表(不含 0、O、I、l)比特币地址、IPFS CID
Ascii85 / Base8585 字符字母表,25 % 开销PDF、PostScript

大多数时候你想要标准或 URL 安全 Base64。其它的会出现在特定协议里。

何时使用 Base64

合适的时候:

不合适的时候:

常见陷阱

替代方案与相邻编码

Base64 是默认,但不是唯一选择。正确选择取决于通道和大小预算。

编码开销优点最适合
十六进制(Base16)100 %易读,每字节两字符调试输出、短标识符、颜色码
Base32(RFC 4648)60 %不区分大小写,无相似字符TOTP 密钥、Onion 地址、口述
标准 Base6433 %通用,每种语言都有邮件、PEM、通用传输
URL 安全 Base6433 %URL 与文件名安全JWT、URL 片段
Base58~37 %无 0/O/I/l 混淆,无特殊字符比特币地址、IPFS CID
Ascii85 / Base8525 %比 Base64 更密PDF、PostScript
Base91~22 %更密,但更复杂少见,小众压缩场景
multipart 上传0 %HTTP 上的原生二进制传输文件上传(浏览器替你做)
gzip + Base64视情况有时比原始 Base64 更小预压缩负载

大多数日常工作的答案是 Base64(标准或 URL 安全)。HTTP 上的二进制文件上传,正确答案通常是 multipart/form-data,它根本不编码。

隐私与编码器

Base64 编码器和解码器完全在你的浏览器里运行。你输入的文本或文件由设备上的 JavaScript 处理,结果渲染到页面上,不向服务器发送任何东西。什么都不会被记录,什么都不会在你离开页面之后保留,也没有分析标签看到内容。对于你可能编码到 Base64 里的东西(PEM 证书、私钥、生产系统的 JWT 负载、含真实客户数据的 API 草稿请求),这种严格本地的流程才是正确的默认值。整套工具一旦页面加载完成就可以离线运行,你可以断网再编码同一份输入来验证这一点。

常见问题

Base64 会加密我的数据吗?

不会。Base64 是编码,而不是加密。任何人都能解码 Base64 字符串 · 它不提供安全性。如果您想保护数据,请使用真正的加密(AES、RSA 等)。

为什么 Base64 让文件变大?

Base64 编码将数据大小增加约 33%。三个二进制字节变为四个 Base64 字符。这是让二进制能作为文本安全传输的代价。

可以编码文件,不仅是文本吗?

可以。任何文件(图像、PDF、音频)都可编码为 Base64。这常用于将小图像作为 data URL 直接嵌入 HTML 或 CSS 中。

什么时候不要使用 Base64?

不要用于大文件。1 MB 的图像作为 Base64 文本会变成 1.33 MB,而且浏览器不能单独缓存它。对于超过几 KB 的任何内容,正常提供文件更高效。

What is the difference between standard Base64 and URL-safe Base64?

Standard Base64 (RFC 4648 section 4) uses the characters A-Z, a-z, 0-9, +, / with = padding. URL-safe Base64 (RFC 4648 section 5) swaps + for - and / for _ so the string is safe to drop into a URL or a filename without percent-encoding. JWT tokens use the URL-safe variant.

Why does Base64 sometimes have one or two = signs at the end?

The = is padding. Base64 encodes input in 3-byte groups; if the input length is not a multiple of 3, the last group is padded with zero bits and one or two = characters mark the missing bytes. One = means one missing byte, two = means two missing bytes.