第 6 课
常见 Base64 错误
字母表混用、换行符、UTF-8 文本解码错误等。
Base64 相关的坑,大多集中在四类:字母表/变体不一致、空白与换行、重复编码,以及把 UTF-8 文本 和 原始字节 混为一谈。
字母表“乱炖”
典型现象:
- 一会儿用标准 Base64(
+//),一会儿用 URL-safe(-/_),随机失败; - 从某处复制来的“像 JWT 的片段”里仍带着
+、/,但服务端按 Base64URL 解析。
治理方式:在代码里 集中封装 编解码路径;为 MIME(有填充)、Base64URL(常无填充) 各准备一组 黄金样例 做往返测试。
不要在多个服务里散落正则“随手替换”——迟早有一条路径忘了 trim 或规范化顺序不对。
大小写敏感
A–Z 与 a–z 在索引表中有不同含义。若对整段载荷误用 .toLowerCase() / .toUpperCase(),会在信息层面 破坏数据。
空白与换行残留
从 PDF、邮件、聊天里复制,常会夹进 软换行、行首行尾空格,甚至 不可见 Unicode 空白(如窄不间断空格、BOM)。
策略:
- 仅在 规范明确允许 时,才使用库提供的“忽略空白”选项;
- PEM 会剥掉头尾
-----BEGIN...行,但 不保证自动处理正文里所有奇怪空格; - 日志切分可能把一条 Base64 截成多行——对异常短的片段要 拒绝或告警。
更稳妥的是:在入口做 显式白名单式规范化(允许哪些字符、如何处理换行),而不是依赖“宽松解码”碰运气。
URL 解码顺序
对查询串先 decodeURIComponent 两次、或和 Base64 规范化 顺序搞反,很容易得到乱码字节——尤其要留意 %2B、%2F、%3D(对应 +、/、=)。
在网关/代理链路里,尽量在框架改写参数 之前拿到原始 query 做诊断。
不小心“套娃”编码
有人把 JSON 先 Base64 一次,拿到字符串后又 再 Base64 一次 存库——最终产物和任何一方的假设都对不上。
在代码与文档里写清 每一层编码的职责(必要时用显式函数名,如 encodeLayer1),并在日志里对敏感值只打印 长度 + 指纹摘要,避免泄露明文。
UTF-8 文本与字节的混淆
“我的中文串被你 Base64 坏了。”常见根因是:
- 对 字符串对象 与 UTF-8 字节序列 的边界理解不清;
- 误用默认代码页(历史上 Windows 区域设置导致 乱码);
- 与服务端 JSON 序列化 是否带 BOM、是否 pretty-print 不一致导致字节不同。
正确心智:
Unicode 字符串 →(按约定,多为 UTF-8)→ 字节 → Base64 → ASCII 文本
每一跳都要明确:这一跳处理的是文本还是 opaque bytes。
JSON 载荷
JSON 在互操作里通常以 UTF-8 字节为准。应对 完整 JSON 文档的字节做 Base64,而不是对“看起来一样”的两种格式化结果想当然。
数据库里的类型
把 Base64 解码后的 protobuf 误存进带排序规则(collation)的 TEXT 列,理论上不该做,但 ORM 误标类型时真的见过 悄悄损坏——能标 BYTEA/BLOB 就别走文本捷径。
安全相关提醒
Base64 不是保密。在不可信链路上只“Base64 一下”等于 明文。
涉及签名 / MAC 时,规范字节布局(包括填充形式、是否 URL-safe)变了,验证会 无声失败——要对 规范级测试向量 做回归。
若比较的是高敏感令牌,避免手写字符串 == 引入时间侧信道——用密码库提供的 常量时间比较(问题不来自 Base64 本身,但常与令牌管道相邻)。
要点小结
团队若要稳,至少对齐这四件事:
- 使用哪套字母表与填充规则(MIME / Base64URL / 其它)
- 解码前的规范化顺序(URL 步骤、去折行策略)
- 内容到底是 UTF-8 文本 还是 不透明字节
- 禁止无文档的 层层套娃编码
把 黄金向量 放进 CI,能在早期抓住回归,而不是靠线上用户帮你试出来。