Base64解释了:它是如何工作的,何时使用它,何时不使用
一个清晰的解释Base64编码:算法,填充,URL安全Base64,数据URL,大小上述,Unicode陷和安全误解。
· 6 分钟阅读
Base64在电子邮件附件,JSON Web Token,数据 URL,Kubernetes 机密,HTTP 基本身份验证以及无数需要通过文本通道移动二进制数据的API中出现。简单一点,但却经常被滥用,。本文将逐步解释算法,常见的变体以及Base64是正确的工具时的实用指导。
这个问题Base64解决了
许多系统的设计目的是传输文本,而不是任意字节。电子邮件 (SMTP) 历史上只支持7位ASCII。JSON字符串不能包含原始二进制。URL和HTTP头有限制的字符集。如果将图像的原始字节放入其中,
Base64 将任意字节映射到 64 个安全可打印字符上:A–Z,a–z,0–9,+ 和/。任何能够传输纯文本的系统都能传输完整的数据。
如何编码工作
Base64处理输入的组为 3 个字节 (24 位),输出 4 个 6 位的字符。因为2^6=64,每个6位值都会从字母表中选择一个字符。
举个例子,Man:
- 亚斯基字节:
M= 77,a= 97,n= 110。 - 在二进制:
01001101 01100001 01101110。 - 分为四个6位组:
010011 010110 000101 101110。 - 作为一个数字:19,22,5,46。
- 查看字母表:
T,W,F,u。
所以Man变成了TWFu。解码会扭转这个过程。
填充用 =
当输入长度不是3的倍数时,最后一个组是不完整的。基64填充它:
- 一个剩余字节产生2个字符加上
==。 - 剩下的2个字节产生3个字符加上
=。
Ma编码为 TWE= 和 M 到 TQ==。填充使得输出长度是四倍的,。其他,尤其是URL安全的实现,会省略它,因为长度已经暗示了缺少多少字节。
大小开支
每3字节就变成4个字符,因此Base64输出大约比输入大33%,加上填充和有时行断 (MIME电子邮件将行包裹在76个字符)。一个1MB的图像大约是1.37MB的文本。这种费用在JSON或HTML中嵌入大型文件时很重要。
网址安全Base64
标准字母包括+和/,在URL中具有特殊含义,以及用于查询字符串的=。Base64URL在RFC 4648中定义,用-取代+和_取代/,通常会丢弃填充。许多API令牌和Web推送键使用这种变体,请参阅[JWT如何工作] (/blog/how-jwt-works)。
标准解码器在-和_上失败,反之亦然,这是"无效字符"错误的常见来源。一个宽容的 [Base64解码器] ((/工具/base64) 接受两个字母,并自动恢复缺失的填充。
文本,字节和Unicode
基64编码字节,而不是字符。要编码文本,首先必须将其转换为字节,。这就是浏览器会让人陷入困境的地方:JavaScript的内置btoa()只接受拉丁-1范围的字符,所以btoa("héllo")是偶然运行的,而btoa("你好")则会出现错误。
在现代JavaScript中正确的方法:
const bytes = new TextEncoder().encode("你好 👋");
const b64 = btoa(String.fromCharCode(...bytes));
const back = new TextDecoder().decode(Uint8Array.from(atob(b64), c => c.charCodeAt(0)));
其他语言明确表示:Python的 base64.b64encode 需要字节,所以你写 base64.b64encode("你好".encode("utf-8"))。
数据URL
数据URL直接嵌入HTML或CSS文件:
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA..." alt="">
这样可以保存HTTP请求,在HTTP/1.1时代是非常有价值的。如今,在HTTP/2多重复用时,平衡通常偏好单独的文件:
- 数据URL不能独立缓存;它们在包含它们的每一个页面或样式表时都会重新下载。
- 它们充满了HTML和CSS,
- 虽然gzip可以恢复部分。
使用数据URL用于微小的资产小图标12 KB以下,占位符图像或单个文件HTML出口。对于任何更大的文件,服务一个正常的文件,而不是[压缩它] (/blog/compress-image-to-100kb)。
Base64不是加密
这就是最重要的一点。基64没有密钥。任何人都可以立即解码,。然而,通常发现:
- 在前端代码中隐藏在Base64中的API键。
- 密码存储在数据库或配置文件中。
- 库伯尼特斯的秘密被认为是受保护的,
Kubernetes 在 Base64 中编码秘密值,以便二进制数据适应 YAML;保护来自访问控制和静止加密,必须单独配置。如果数据需要保密,请使用AES-GCM这样的真实算法加密,如果需要验证密码,请使用密码哈希函数而不是Base64而不是像MD5这样的简单哈希 (为什么不)。
常见的用例做得很好
- HTTP基本身份验证 发送
Authorization: Basic base64(user:password)。编码只能避免特殊字符的问题;凭证仅由HTTPS保护。 - 电子邮件附件使用MIME Base64,每76个字符都会有行断。
- 将二进制数据嵌入JSON中,例如一个小的签名图像或密码密钥,是合法的使用。对于大型文件,单独上传并通过URL引用它们。
- 仅存储文本配置中的二进制数据,例如环境变量中的TLS证书。
解码错误的故障排除
- **不有效的字符:**您可能使用标准解码器解码Base64URL,或者字符串包含空白或行断。
- 不正确的填充: 加入
=直到长度是四的倍数。 - **解码后出现错误的文本:**原件是从不同的字符集编码的,或者数据是二进制而不是文本。
- **输出看起来像Base64:**数据被编码两次;再一次解码。
相关编码
- Base32使用32个字符 (AZ和27),不敏感大写,用于身份验证应用程序的TOTP秘密。总费用是60%。
- 十六进制 (Base16) 每字节使用两个字符 100% 总额但易于阅读,并且用于哈希。
- Base58删除类似字符,用于比特币地址。
- 百分比编码只逃离URL中的不安全字符。
总结
Base64将字节转换为64个字符的文字字母,一次3个字节,成本约为33%的额外大小。使用它通过文本道传输二进制数据;在URL和令牌中使用URL安全变体;始终首先将文本转换为UTF-8字节。永远不要使用它来保护秘密,这是一个加密,不是锁。
本页内容由英文自动翻译而来,如发现错误,欢迎告诉我们。