Base64 URL 安全编码:它是什么以及为什么重要
什么是 Base64 URL 安全编码?
Base64 URL 安全编码(也称为 Base64url)是标准 Base64 的一种变体,它将 URL 和文件名中具有特殊含义的字符替换为安全的替代字符。标准 Base64 使用 + 和 / 作为其 64 字符字母表的一部分,外加 = 用于填充,这三个字符在 URL、查询字符串和文件路径中都有问题。
Base64url 通过两个简单的替换解决了这个问题:
| 标准 Base64 | URL 安全 Base64 |
|-----------------|-----------------|
| +(加号) | -(减号) |
| /(斜杠) | _(下划线) |
| =(填充) | 省略(通常) |
为什么标准 Base64 会破坏 URL
当包含 + 或 / 的 Base64 编码字符串出现在 URL 中时,浏览器和服务器的行为会变得不可预测。
+ 问题
在 URL 查询字符串中,+ 字符被解释为空格。这种行为来自 application/x-www-form-urlencoded 规范,并会导致解码后的数据包含意外的空格。
例如,像 Pj4+Pz8/Pw== 这样的 Base64 字符串包含 + 字符。如果它出现在 URL 参数 ?token=Pj4+Pz8/Pw== 中,服务器将看到 ?token=Pj4 Pz8/Pw==——+ 变成了空格。
/ 问题
在 URL 路径中,/ 字符是路径分隔符。像 ab/CD+Ef== 这样的 Base64 字符串包含一个 /,它将被解释为目录层级。如果它出现在 URL 段中,客户端和服务器都可能错误地理解其结构。
= 问题
= 字符在查询字符串中用于键值对。?data=SGVsbG8= 中末尾的 = 可能产生歧义——这个 = 是 Base64 填充的一部分还是查询参数的语法?
虽然百分号编码可以解决这些问题(+ 变为 %2B,/ 变为 %2F),但它会膨胀字符串长度并使调试变得更加困难。Base64url 是更干净的解决方案。
Base64url 如何工作
Base64url 在 RFC 4648 第 5 节中正式定义。它使用与标准 Base64 完全相同的算法——3 字节变为 4 个字符——但字母表第 62 和 63 位的位置各替换一个字符:
- 字母表索引 62:
+→-(减号) - 字母表索引 63:
/→_(下划线)
填充(=)通常被去除,因为解码时可以从字符串长度推断出来。Base64url 字符串始终是有效的 URL 组件,无需额外的转义。
转换前后对比
以下是相同的二进制数据在两种格式下的样子:
标准: Pj4+Pz8/Pw==
URL 安全: Pj4-Pz8_Pw
Base64url 的用途
JSON Web Token(JWT)
JWT 是 Base64url 最突出的使用者。每个 JWT 由三部分组成——header、payload 和 signature——每部分都经过 URL 安全 Base64 编码并用点分隔:
eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.dozjgNqP0m2iTgCjD0
注意其中的短横线和下划线——没有加号或斜杠。如果 JWT 使用标准 Base64,令牌在作为 URL 参数传递时会失效,而这是它们在 Web 应用中最常见的使用方式。
OAuth 和 OpenID Connect
OAuth 2.0 和 OpenID Connect 都依赖 JWT 作为访问令牌和 ID 令牌,使得 Base64url 编码成为现代认证的基础。授权码流程、隐式流程和客户端凭证流程都会传输使用 Base64url 的令牌。
Web API 和查询参数
许多 REST 和 GraphQL API 在查询参数中接受 Base64 编码的数据,用于分页游标、过滤器或编码负载。Base64url 确保这些参数无需额外的 URL 编码即可正常工作。
真实示例——API 游标分页:
GET /api/users?cursor=MjAyNC0wMS0xNVQxMDozMDowMFo
GitHub 的 API 使用这种精确的模式对大型结果集进行分页。
文件名和文件存储
Base64url 字符串可以安全地用作文件名,因为它们不包含路径分隔符(/)、不会混淆文件系统的特殊字符,也不包含在 Windows 上无效的字符(:、*、? 等)。
内容分发网络和缓存键
CDN 和缓存层经常使用 Base64url 编码的值作为缓存键。包含 / 的标准 Base64 会在缓存命名空间中创建虚假的目录层级,导致键出现歧义。
在标准 Base64 和 Base64url 之间转换
在两种变体之间转换在任何语言中都很简单:
JavaScript
// 标准 Base64 转 URL 安全 Base64
function base64ToBase64url(base64) {
return base64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
}
// URL 安全 Base64 转标准 Base64
function base64urlToBase64(base64url) {
let result = base64url.replace(/-/g, '+').replace(/_/g, '/');
// 恢复填充
while (result.length % 4) {
result += '=';
}
return result;
}
Node.js
Node.js 自 15.7.0 版本起提供原生的 Base64url 支持:
// 编码为 Base64url
const encodedUrl = Buffer.from('Hello, world!').toString('base64url');
console.log(encodedUrl);
// 输出:SGVsbG8sIHdvcmxkIQ
// 从 Base64url 解码
const decoded = Buffer.from(encodedUrl, 'base64url').toString('utf-8');
console.log(decoded);
// 输出:Hello, world!
Python
import base64
# 编码为 Base64url
encoded = base64.urlsafe_b64encode(b"Hello, world!")
print(encoded.decode())
# 输出:SGVsbG8sIHdvcmxkIQ==
# 从 Base64url 解码
decoded = base64.urlsafe_b64decode(encoded)
print(decoded.decode())
# 输出:Hello, world!
何时使用标准 Base64 与 Base64url
使用标准 Base64 的情况:
- 编码电子邮件附件(MIME 标准要求使用)
- 为 HTML/CSS 嵌入生成 data URL
- 在 URL 安全性无关紧要的数据库中存储数据
- 与期望标准 Base64 的遗留系统交互
使用 Base64url 的情况:
- 创建或解析 JWT 令牌
- 在 URL 查询参数或路径段中传递编码数据
- 从二进制数据生成文件名
- 创建缓存键或标识符
- 使用 OAuth 令牌或 OpenID Connect
在线尝试 Base64 URL 安全编码
使用我们的免费在线 Base64 编码器和解码器在标准 Base64 和 URL 安全 Base64 格式之间转换。粘贴你的数据,选择变体,立即获得结果。