Base64 與 Base64URL 有甚麼分別?補齊字元、URL 編碼與 RFC 4648
DDEVELOPER
開發發布: 8 分鐘閱讀

Base64 與 Base64URL 有甚麼分別?補齊字元、URL 編碼與 RFC 4648

同樣是把二進制資料轉成文字,Base64 與 Base64URL 並不能在任何位置直接互換。網址查詢參數、檔案名稱、電子郵件附件及 JWT 對字元與補齊的要求各有不同。本文以 RFC 4648 為基礎,解釋 +/= 何時需要處理,以及怎樣避免編碼與解碼兩端對規則有不同理解。

日文原文發布: 2026-04-19

Base64 如何運作?

Base64 將輸入的二進制資料切成每組 6 位元,再將每組數值對應到 64 個可打印字元之一。

  • 輸入:任意位元組序列。
  • 輸出字元:A-Z a-z 0-9 + /,另以 = 補齊。

3 個位元組共有 24 位元,可拆成 4 組 6 位元,輸出 4 個 ASCII 字元。包含補齊字元時,長度為 4 × ceil(輸入位元組數 / 3)。輸入夠長時,輸出字元數約為原始位元組數的 4/3。這不代表 4 個輸出字元只占 24 位元:儲存或傳輸文字時,通常每個 ASCII 字元至少需要 1 個位元組。輸入長度不是 3 的倍數時,最後一組以 1 或 2 個 = 補滿 4 個字元。

// "ABC"(3 位元組)→ "QUJD"(4 字元)
// "AB" (2 位元組)→ "QUI="(補 1 個等號)
// "A"  (1 位元組)→ "QQ=="(補 2 個等號)

RFC 4648 的兩種 Base64 字元表

如表格未能完整顯示,可左右捲動。

編碼數值 62數值 63補齊規則章節
標準 Base64+/=§4
Base64URL(base64url)-_引用此編碼的規格允許時,才可省略§5

Base64URL 將 +/ 換成 URI 的非保留字元 -_。加號不是在所有網址中都會變成空格,而是在以 application/x-www-form-urlencoded 規則解析時才會如此轉換。查詢字串中的斜線也不一定是路徑分隔符號;但放在路徑片段或檔案名稱裡,就可能與其結構或慣例衝突。

陷阱一:把標準 Base64 直接串接到網址

直接串接並不可靠。需要特殊處理哪些字元,取決於資料位於查詢參數、路徑、表單編碼內容,或其他網址元件。

// 表單式查詢解析可能把 + 轉成空格
https://example.com/api?token=AA/+AA==

// 必須使用標準 Base64 時,對參數值進行百分比編碼
https://example.com/api?token=AA%2F%2BAA%3D%3D

// URLSearchParams 會對參數值套用表單式編碼
new URLSearchParams({ token: "AA/+AA==" }).toString();
// "token=AA%2F%2BAA%3D%3D"

如果可以自行決定資料格式,Base64URL 能減少需要百分比編碼的字元,但是否補齊是另一個問題。RFC 7515 規定 JWS 的 base64url 值省略所有尾端 =。JWT 以 JWS 或 JWE 物件表示,而 JWE 也採用不補齊的 base64url。

// btoa() 接受的是每個字元碼代表一個位元組的二進制字串。
// 任意 Unicode 文字必須先轉成 UTF-8 位元組。
// 輸入含有 / 或 +,不代表輸出一定含有這些符號;
// 輸出的 6 位元數值為 63 或 62 時,才會出現它們。
const standard = btoa("Subjects?"); // "U3ViamVjdHM/"
const urlSafe = standard.replace(/\+/g, "-")
                        .replace(/\//g, "_")
                        .replace(/=+$/, ""); // "U3ViamVjdHM_"

陷阱二:以為補齊字元永遠可以省略

RFC 4648 §3.2 的預設規則是:除非引用此編碼的規格明確允許,否則編碼器必須加入適當的補齊字元。§5 說明,在資料長度可隱含確定時可以省略。因此,「Base64URL 一律不帶等號」並不是通則,必須由雙方約定或 JWS 等規格明確定義。

JWS、JWE 與 JWT 依規格採用不補齊的 base64url。解碼器可以從長度推回所需等號數量,但去掉尾端補齊字元後,長度除以 4 餘 1 的輸入不可能是有效的 base64url

// 接受有補齊或無補齊的輸入,並要求正規編碼。
function decodeBase64Url(value) {
  const match = /^([A-Za-z0-9_-]*)(={0,2})$/.exec(value);
  if (!match) {
    throw new Error("Invalid base64url");
  }
  const body = match[1];
  const explicitPadding = match[2];
  if (body.length % 4 === 1) {
    throw new Error("Invalid base64url length");
  }
  const requiredPadding = (4 - body.length % 4) % 4;
  if (explicitPadding.length !== 0 && explicitPadding.length !== requiredPadding) {
    throw new Error("Invalid base64url padding");
  }
  const standard = body.replace(/-/g, "+").replace(/_/g, "/")
                       + "=".repeat(requiredPadding);
  const decoded = atob(standard); // 二進制字串;UTF-8 文字需另行解碼。
  const canonical = btoa(decoded).replace(/\+/g, "-").replace(/\//g, "_")
                                 .replace(/=+$/, "");
  if (canonical !== body) {
    throw new Error("Non-canonical base64url");
  }
  return decoded;
}

此例接受無等號的輸入,或尾端等號數量恰好正確的輸入。將解碼結果重新編碼並比對,可拒絕未使用的補齊位元(pad bits)不為零的非正規表示。另一方面,只接受標準補齊 Base64 的解碼器可能拒絕無等號輸入;介面兩端必須明確約定補齊規則。

陷阱三:混淆 MIME 換行與 RFC 4648 輸出

RFC 2045 規定 MIME Base64 每行不得超過 76 個字元,以 CRLF 分行。

相對地,RFC 4648 規定,除非引用規格有要求,否則編碼器不得自行加入換行。Python 的 base64.encodebytes() 與 OpenSSL 的 base64 指令都可能產生分行輸出。接收端若要求單行,就應在產生資料時關閉自動換行。解碼器對字元表以外的字元也有不同處理方式,不能把事後移除空白字元(例如空格與換行)當成所有介面通用的解法。

# Python:單行輸出
import base64
encoded = base64.b64encode(data).decode()
# encodebytes() 採用 MIME 風格分行。
# encodestring() 已於 Python 3.9 移除。

// Node.js:單行輸出
const encoded = Buffer.from(data).toString("base64");

# OpenSSL:-A 關閉自動換行
openssl base64 -A -in input.bin

RFC 4648 還有哪些編碼?

  • Base32(§6):A-Z 2-7,不使用數字 01,可減少它們與字母 OIL 混淆的機會;但 ILOS 仍在字元表中。
  • Base32 Extended Hex(§7):0-9 A-V,編碼字串能保留原始資料按位元比較的排序順序。
  • Base16(§8):使用 0-9 A-F 的十六進制編碼。

輸入夠長時,Base64 輸出字元數約為輸入位元組數的 4/3,Base32 約為 8/5,Base16 則為 2 倍。這些是編碼,不是壓縮;應依允許的字元、互通性、可讀性與長度成本選擇。

依使用情境選擇

如表格未能完整顯示,可左右捲動。

用途常見形式依據
電子郵件附件標準 Base64,每行最多 76 字元RFC 2045 MIME
HTTP Basic 認證資料標準 Base64RFC 7617
網址查詢參數或路徑Base64URL;依上層規格決定補齊RFC 4648 §3.2、§5
JWS、JWE、JWT不補齊的 Base64URLRFC 7515、7516、7519
檔案名稱Base64URL避開標準 Base64 的斜線
Data URL標準 Base64RFC 2397

Base64 不是加密,也不提供機密性。任何人都能解碼,不能用它保護密碼、API 金鑰、個人資料或其他機密。

重點整理

  • RFC 4648 §4 定義標準 Base64,§5 定義 base64url 字元表。
  • Base64URL 將 +/ 換成 -_;是否省略等號,仍須依約定或引用規格。
  • 加號變空格是表單式解析的行為,不是網址語法的通則。
  • JWS、JWE 與 JWT 採用不補齊的 base64url。
  • MIME Base64 每行最多 76 字元,RFC 4648 則預設不換行。
  • Base64 是編碼,不是加密。

參考資料及來源

編輯說明

本文使用 AI 協助編輯,並在發布前由編輯核對。內容仍可能包含事實、理解或時效上的錯誤;作出重要決定前,請查閱所列的一手資料或官方文件。

相關文章