UUsefulCrate 你的文件永远不会离开浏览器

首页 › 指南 › 开发者

Base64 不是加密

Base64 在软件里随处可见,被误解的频率几乎和它被使用的频率一样高。这些误解没有一个难解释。

2026-09-24 · 7 分钟阅读

直接给结论:不是。Base64 是一种编码,不是密码。 它把任意字节变成能在「只传文本」的通道里活下来的文本 —— 邮件正文、JSON 字段、data URL —— 而任何人都能不用任何密钥就把它还原。它还会让数据大约变大三分之一, 因为它用四个字符来承载三个字节。

一串看起来像乱码的字符、由一个叫「encode」的函数生成,很容易被误当成某种保护措施。 Base64 不提供保护。它是一种传输格式,而误解这一点的代价是实实在在的。

Base64 实际做了什么

Base64 用 64 个可打印字符构成的字符表来表示任意字节:大小写字母、十个数字, 再加上 + 和 /,末尾用 = 补位。

它的目的是把二进制数据送过那些「只运文本」的通道。邮件正文、JSON 的值、XML 文档、 HTTP 头、URL,这些都各自规定了哪些字节是允许的。 Base64 把任意字节序列变成一段同时满足上述所有规则的序列。

"hello"        → aGVsbG8=
0x00 0xFF 0x10 → AP8Q
café           → Y2Fmw6k=     (UTF-8 字节:63 61 66 C3 A9)

误解一:它不是加密

编码是一种不需要密钥的可逆变换。拿到那串字符的任何人,都能立刻用一个每种语言都自带的功能把它解回去。 整个过程不涉及任何秘密。

判断方法很简单:如果解回去只需要那段编码后的文本,那它就是编码。加密需要密钥, 没有密钥时它的输出与随机噪声无法区分。

这个错误在生产环境里出现的频率,比人们希望的要高。带 Basic 凭据的授权头就是 Base64 —— 标准甚至把里面的内容叫作「凭据」,而任何看到这个头的人都能读出来。 以 Base64 字符串形式存在配置文件里的 API 密钥,就是一个 API 密钥。 混淆不是一种安全控制,而这是它最常被误当成控制的地方。

误解二:它不会让任何东西变小

恰恰相反。Base64 用 4 个字符承载 3 个字节,所以输出恰好是输入体积的 4/3 —— 大约大 33%,还没算换行符。

「它一定压缩了什么」这个直觉,来自输入通常是二进制、看起来本来就晦涩。 但长度是每次都增大,而且是确定的。把一张图片以 Base64 塞进 JSON, 会让载荷胖三分之一,而 JSON 解析器之后还得再把它解回字节。

那为什么「base64 压缩」有时候看起来真的有效

因为被测的是那一次开了 gzip 的 HTTP 响应。Base64 的输出只用了 64 个可打印字符, 字符集很小,压缩率自然高。所以网络传输体积确实会降 —— 但这份节省来自 gzip, 而不是来自 Base64;而 gzip 处理原始二进制至少一样有效。

误解三:那串「像加密过」的补位符有含义

结尾的 = 或 == 不是校验和、不是密钥提示、也不是安全标记。 它存在的原因是:输入长度不一定能被 3 整除,而这个编码是按三个字节一组处理的。 多出一个字节就产生两个补位符,多出两个字节就产生一个,正好整除就一个都没有。

它确实携带了一点信息:补位符告诉你原始长度模 3 是多少。仅此而已。

误解四:任意两个 Base64 工具结果都一样

有两个变体,把它们搞混会得到一段解不开、而且报错信息很迷惑的输出。

标准版URL 安全版
第 62 个字符+-
第 63 个字符/_
补位符=通常省略
用在哪邮件(MIME)、data URI、多数 APIJWT、URL、文件名

URL 安全版存在的原因,是 + 和 / 在 URL 里有特殊含义 —— + 在表单编码里代表空格,/ 是路径分隔符。 所以一段标准版 Base64 粘进查询参数或路径片段后,可能在传输过程中被悄悄改掉, 而在你的服务器看到它之前就已经变了。

这就是 JWT 采用 URL 安全字符表的原因。也是「从浏览器复制的 token 和服务器端看到的不一样」的原因 —— 如果中间某一段把 + 当成了空格的话。这里的 Base64 编解码工具有一个明确的 URL 安全开关,让这个选择是主动做出的。

误解五:用 Base64 存数据挺合理

把图片以 Base64 字符串存进数据库字段是个常见的顺手做法,代价有三项: 这个字段比需要的多占 33% 的字节;数据库没法对它做有意义的索引和检索; 每一次读取都要多付一步解码。

CSS 和 HTML 里的 data URI 是这类做法中偶尔说得过去的一种,因为它省掉了一个请求, 而这在资源确实很小时是划算的。超过一两 KB 之后,这笔交易就变成负的, 而且你会失去「单独缓存这张图」的能力。

Base64 用对的地方

所有这些情况的动机都一样:目的地只接受文本。没有一个是关于保密的。

一句话总结

Base64 让数据变得可以安全地传输。它既不让它变小,也不让它变秘密。

如果你需要保密,你需要加密,以及一把从不经过传输通道的密钥。 如果你需要完整性,你需要签名或者哈希。 Base64 两者都给不了,而把它当成都给,正是凭据出现在日志和配置文件里、 并且被人误以为「可以放心分享」的原因。

就编码本身而言,在本地做能避开一个很具体的问题:这种操作的输入非常经常就是秘密 —— 一个被嵌进配置的 API 密钥、一个要放进请求头的 token、一条连接字符串里的密码。 这里的编解码工具能正确处理 UTF-8,这比听起来重要: 很多工具编码的是字符本身而不是它们的 UTF-8 字节,结果解出来是乱码。 带音标的字母、emoji 和中文在这里都能正确往返。

← 全部指南