🔐
← 返回教程列表

Base64 URL 安全编码:它是什么以及为什么重要

· 标签: base64, url-safe, base64url, jwt, encoding, web-development, api

什么是 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 格式之间转换。粘贴你的数据,选择变体,立即获得结果。