如何进行 Base64URL 编码
- 在 输入 · 文本 中输入或粘贴文本。
- 从 输出 · Base64 中复制 Base64URL。本页已勾选 URL 安全(- _) 和 不填充(=)。
- 如果接收方需要填充,取消勾选 不填充(=)。如果需要标准 Base64,再取消勾选 URL 安全,或者使用 Base64 编码器。
- 复制输出,或下载为
base64.txt。
解码请使用 Base64URL 解码器。Base64 转 Base64URL 可以在两种字母表之间转换现有字符串。
与标准 Base64 相比有什么不同
只有三个字符不同。其他一切,包括 3 个字节变 4 个字符的规则,都保持不变:
| 标准 Base64 | Base64URL | |
|---|---|---|
| 值 62 | + | - |
| 值 63 | / | _ |
| 填充 | 必须有 = | 通常省略 |
| 定义于 | RFC 4648 第 4 节 | RFC 4648 第 5 节 |
对于很多短字符串,两种变体只在填充上有区别。只要某个 6 位分组的值为 62 或 63,字母表的差异就会显现出来,?、> 这类字符和许多非 ASCII 字节都会产生这样的分组:
| 输入 | 标准 | Base64URL,无填充 |
|---|---|---|
Hi! | SGkh | SGkh |
?>?> | Pz4/Pg== | Pz4_Pg |
subjects?_d | c3ViamVjdHM/X2Q= | c3ViamVjdHM_X2Q |
https://example.com/?q=1 | aHR0cHM6Ly9leGFtcGxlLmNvbS8/cT0x | aHR0cHM6Ly9leGFtcGxlLmNvbS8_cT0x |
Base64 与 Base64URL 的区别 更深入地介绍了它的由来和解码上的差异。
为什么 URL 需要专门的字母表
这三个标准字符在 URL 中都有特殊含义。/ 分隔路径段,= 在查询字符串中分隔名称和值,+ 会被表单解码器读作空格。像 a+b/c== 这样的标准 Base64 值放进查询参数,除非每个字符都做了转义,否则到达时会变成 a b/c==。百分号编码可以解决这个问题,但每个字符都会变成三个字符(%2B、%2F、%3D)。
Base64URL 选用了两个在 URL 中不保留的字符,并去掉了填充,因此可以原样粘贴到路径、查询字符串、片段、Cookie 或文件名中。与 / 不同,- 和 _ 在所有常见文件系统的文件名中也都是安全的。
Base64URL 用在哪里
- JWT 和 JOSE。 JSON Web Token 的每个部分都是不带填充的 Base64URL,由 RFC 7515 定义。JWT 解码器 可以读取令牌;JWT 中的 Base64 讲解了它的结构。
- OAuth PKCE。
code_challenge是code_verifier的 SHA-256 哈希的 Base64URL。 - WebAuthn 和通行密钥。 凭据 ID 和质询以 Base64URL 形式放在 JSON 中传输。
- 链接和 ID。 分享链接、签名的 URL 参数,以及由随机字节生成的短 ID 都用它来保持 URL 干净。
在代码中使用 Base64URL
Node.js 内置了 base64url 编码;Python 有 URL 安全的函数,但填充需要你自己去掉:
// Node.js
Buffer.from("subjects?_d").toString("base64url"); // "c3ViamVjdHM_X2Q"
// Browsers with Uint8Array.prototype.toBase64
new TextEncoder().encode("subjects?_d").toBase64({ alphabet: "base64url", omitPadding: true });
import base64, hashlib
base64.urlsafe_b64encode(b"subjects?_d").rstrip(b"=").decode() # 'c3ViamVjdHM_X2Q'
# PKCE code_challenge, example from RFC 7636 appendix B
verifier = "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk"
digest = hashlib.sha256(verifier.encode("ascii")).digest()
base64.urlsafe_b64encode(digest).rstrip(b"=").decode()
# 'E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM'
详见 Node.js 中的 Base64、JavaScript 和 Python,浏览器 API 请参阅 Uint8Array.toBase64。
常见问题
什么是 Base64URL?
它是 RFC 4648 第 5 节定义的 Base64 变体,可安全用于 URL 和文件名。字母表的最后两个字符用 - 和 _ 代替 + 和 /,而且通常不写 = 填充。
为什么不直接对普通 Base64 做百分号编码?
这样可行,但每个 +、/ 和 = 都要占三个字符;而且只要漏掉一次转义,解析查询字符串时 + 就会变成空格。Base64URL 避免了这两个问题。
要不要保留 = 填充?
JWT 和大多数 URL 安全格式都省略填充,因为 = 在 URL 中同样需要转义,而解码器可以根据长度推算出填充。只有接收方要求时才保留:取消勾选“不填充(=)”。
怎么生成 PKCE 的 code_challenge?
用 SHA-256 对 code_verifier 计算哈希,再把 32 个哈希字节编码为不带填充的 Base64URL。本页编码的是文本而不是哈希字节,所以请在代码中完成;下面的代码片段复现了 RFC 7636 中的示例。