← 返回文章列表

Base64 是编码不是加密:何时该用

编码避坑

Base64 做了什么

它把每 3 字节二进制变成 4 个可打印字符,目的只是让数据能安全地放进只认文本的协议(邮件、JSON、URL)。它不提供任何保密性。

该用的时候

  • 在 JSON 里传图片或文件内容(data URL、附件);
  • 把证书、令牌塞进文本配置;
  • 需要肉眼可逆地表示二进制。

别这样用

  1. 当加密用:谁都能解码,等于明文;敏感内容请用 AES 等;
  2. 忽略体积:体积增大约 33%,大文件别硬塞进 JSON;
  3. 当作压缩:Base64 反而变大,压缩请用 gzip。

动手试试

编码与解码:Base64 编解码。

实战案例:三个用错 Base64 的场景

  1. 把 Base64 当加密:接口返回 eyJpZCI6MX0= 就以为“破解不了”,实际一行解码即可还原。要保密用 AES,要防篡改用签名。
  2. 大图内联拖慢首屏:把 500KB 的图转成 data URI 塞进 CSS,体积增大约 33%,还无法单独缓存与并行加载。几 KB 的小图标可内联,大图仍应走独立文件。
  3. URL 里直接塞标准 Base64:+、/、= 会被转义或截断,导致参数错位。放进 URL 请改用 URL 安全变体(+ 换成 -、/ 换成 _ 并去掉 =)。

常见问题(FAQ)

Base64 能压缩吗?不能,反而让体积增大约 33%。为什么编码后长度是 4 的倍数?因为每 3 字节映射为 4 个字符,不足时用 = 补齐。中文直接 btoa 为什么报错?btoa 只接受 Latin-1,中文须先用 TextEncoder 转成字节。适合在数据库里长期存大字段吗?不适合,既占空间又难查询,应改用二进制字段或对象存储。

体积与性能实测

Base64 的代价能量化,决策就不靠感觉:

  • 体积:编码后原始数据增长约 33%(4/3),再叠加换行与填充会再多几个百分点;
  • 内存:字符串形式的 Base64 在 JS 里按 UTF-16 存放,实际内存占用可能是原始字节的两倍以上;
  • 压缩:JSON 里的大段 Base64 用 gzip 传输收益很大(Base64 字符集小、重复度高),但压缩只能弥补传输,弥补不了内存;
  • 解析:浏览器解码 data URI 需要先解析字符串再转字节,大对象会阻塞主线程,数 MB 以上建议改用 Blob 或直接走后端接口。

用流式思路处理大文件

Node 里不要用 readFileSync 读整文件再转 Base64,改用流式编码:逐块 chunk.toString('base64') 并注意每块长度必须是 3 的倍数,否则块边界会产生错误的填充。浏览器里可用 FileReader.readAsDataURL 或 Blob 配合 URL.createObjectURL,避免把大对象整体放进内存。

判断该不该用的三个问题

  1. 这段数据**必须**经过只能传文本的通道吗?不是就别编码;
  2. 它是不是小于几 KB?更大就用二进制或独立文件;
  3. 它是**长期存储**还是**一次性传输**?长期存储应放对象存储,字段里只存引用。

跨端兼容性注意

  • 换行与空白:MIME 风格的 Base64 会每 76 字符换行,解码前应先剔除空白与换行,否则解析失败;
  • URL 安全变体:- 与 _ 版本与标准版本不通用,混用会解码出错,转换时记得做替换;
  • 填充可选:部分实现允许省略 =,但严格解码器会拒绝,跨系统传输时建议保留填充;
  • 大小写敏感:Base64 区分大小写,任何“顺手转小写”的处理都会破坏数据。

安全边界提示

Base64 常被误当作“轻度混淆”。请记住它不提供任何保密性:任何看到密文的人都能立即还原。若确实需要防止“被顺手看到”,至少应使用带密钥的加密或签名,并明确区分“编码”与“加密”在合规与审计中的不同含义。

与压缩的配合顺序

若既要压缩又要编码,顺序是“先压缩再 Base64”。反过来先编码会破坏原始数据的重复性,压缩率大幅下降,体积甚至比不压缩更大。同理,解码时应 Base64 解码后再解压。

与日志的关系

把 Base64 结果直接写进日志会显著增加日志体积并降低可读性,排查时也难以对照原文。若必须记录,建议同时保存原文摘要与长度,或仅在调试级别输出,避免长期占用存储与索引资源。