
Base64 與 Base64URL 差在哪?RFC 4648、補齊字元與網址編碼陷阱
RFC 4648 定義的 Base64,能把二進位資料表示成可列印的 ASCII 字元,常見於 JWS、JWT、電子郵件附件與 data URL。真正容易出錯的是使用情境:把一般 Base64 直接放入網址或檔名時,可能需要另外處理 +、/ 或 =。本文整理標準 Base64 與 Base64URL 的差別,以及三個常見的互通性問題。
日文原文發布: 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.binRFC 4648 還有哪些編碼?
- Base32(§6):
A-Z 2-7,不使用數字0與1,可減少它們與字母O、I或L混淆的機會;但I、L、O、S仍在字元表中。 - 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 認證資料 | 標準 Base64 | RFC 7617 |
| 網址查詢參數或路徑 | Base64URL;依上層規格決定補齊 | RFC 4648 §3.2、§5 |
| JWS、JWE、JWT | 不補齊的 Base64URL | RFC 7515、7516、7519 |
| 檔名 | Base64URL | 避開標準 Base64 的斜線 |
| Data URL | 標準 Base64 | RFC 2397 |
Base64 不是加密,也不提供機密性。任何人都能解碼,不能用它保護密碼、API 金鑰、個人資料或其他機密。
重點整理
- RFC 4648 §4 定義標準 Base64,§5 定義 base64url 字元表。
- Base64URL 將
+、/換成-、_;是否省略等號,仍須依約定或引用規格。 - 加號變空白是表單式解析的行為,不是網址語法的通則。
- JWS、JWE 與 JWT 採用不補齊的 base64url。
- MIME Base64 每行最多 76 字元,RFC 4648 則預設不換行。
- Base64 是編碼,不是加密。
參考資料與來源
- RFC 4648 — The Base16, Base32, and Base64 Data Encodings ↗
- RFC 7515 — JSON Web Signature (JWS) ↗
- RFC 7516 — JSON Web Encryption (JWE) ↗
- RFC 7519 — JSON Web Token (JWT) ↗
- RFC 2045 — Multipurpose Internet Mail Extensions (MIME) ↗
- WHATWG URL Standard — application/x-www-form-urlencoded 解析 ↗
- RFC 7617 — The Basic HTTP Authentication Scheme ↗
- RFC 2397 — The data URL scheme ↗
- Python 官方文件 — Base64 encodings ↗
- OpenSSL 官方文件 — openssl-enc ↗
編輯說明
本文使用 AI 協助編輯,並於發布前由編輯確認。內容仍可能包含事實、解讀或時效上的錯誤;進行重要判斷前,請查閱所列的一手資料或官方文件。

