末尾が == で終わる長い文字列と数字の羅列を見て、それが何か疑問に思う。JWT をツールに貼り付けると、中央部分がほぼ読める状態になっている。HTMLメールに画像を埋め込むと、src 属性は文字の壁になる。PDF を API にアップロードすると、ドキュメントには「Base64として送信してください」と書かれている。これらはすべて同じエンコーディングであり、ほとんどの開発者はその仕組みを本当に理解しないまま使っている。
このガイドでは、Base64が実際に何であるか、いつ使用すべきか、よくある間違い(最大の間違いである暗号化と誤解することも含む)、URLセーフなバリアント、パディングルール、および主要な各言語でのエンコードとデコードの方法について説明します。
Base64とは
Base64は、64の特定の文字を使用してバイナリデータをASCIIテキストに変換するエンコーディングです:A-Z, a-z,0-9、プラス+と/。=文字は、末尾のパディングに使用されます。入力の3バイトごとに、出力は正確に4文字のBase64文字になります。つまり、Base64はデータサイズを約33%増加させます。
Input bytes: "Hi" (2 bytes: 0x48 0x69)
Binary: 01001000 01101001
Group in 6s: 010010 000110 1001(00) ← last group padded with zeros
Base64 chars: S G k = ← '=' = padding
Result: "SGk="
数学:64文字ということは、各文字が6ビットを表す。6ビット(Base64の1文字)と8ビット(1バイト)の最小公倍数は24ビットであり、これは3バイトまたは4つのBase64文字に相当する。これが、Base64が常に4つの出力文字のグループで機能し、パディングが存在する理由である。
最大の誤解:Base64は暗号化ではない。
これは開発者も非開発者も同様に魅了します。Base64は意味不明に見えるので、秘密のように感じられます。しかし、そうではありません。誰でも瞬時にBase64をデコードできます — 鍵もパスワードも解読すべきアルゴリズムもありません。それは透明な変換であり、別のアルファベットで書くようなものです。
// "Encrypted" password?
"cGFzc3dvcmQxMjM="
// Decoded in one line
atob("cGFzc3dvcmQxMjM=")
// → "password123"
Base64はエンコーディングであり、暗号化ではありません。それを使って 転送する テキストのみのチャネルを介して安全にデータを転送します — データを 隠す ことは決してありません。機密性が必要な場合は、実際の暗号化を使用してください:転送中のデータにはAES、NaCl/libsodium、またはTLSを使用します。
Base64を使用するタイミング
Base64は、テキストを期待するシステムを通してバイナリデータを移動するために存在します。最も一般的なケース:
JSONまたはXMLにバイナリを埋め込むこと。— どちらのフォーマットも生のバイトをサポートしていません。JSONペイロードの一部としてファイルアップロードを受け付けるAPIは、ファイルを表すためにBase64を使用します。
HTML/CSS内のデータURL次のテキストを英語から日本語に翻訳してください:
—data:image/png;base64,iVBORw0KGgo...別途HTTPリクエストを行うことなく、画像をインラインで埋め込むことができます。小さなアイコンやメール署名に便利です。
HTTP基本認証— ザAuthorizationヘッダーが認証情報を送るとしてBasic <base64-of-username:password> これは、Base64が暗号化ではない理由の完璧な例でもあります。Basic AuthはHTTPSと組み合わせた場合のみ安全です。
JWT — JSON Web Tokenは、ドットで区切られた3つのBase64URLエンコードされたセクションで構成されています。ヘッダーとペイロードは読み取り可能なJSONですが、署名部分だけが不透明です。
メールの添付ファイル — SMTPは技術的には7ビットのテキストプロトコルであるため、MIME標準以降、添付ファイルはデフォルトでBase64エンコードされています。
暗号鍵と証明書 — PEMファイル(-----BEGIN CERTIFICATE-----ブロック)はBase64エンコードされたバイナリ鍵をラップします。
パディング — なぜ一部のBase64は=で終わり、一部はそうでないのか
その= Base64文字列の末尾にあるのはパディングです。これは、Base64が3バイトの入力単位で動作し、すべての入力が3バイトの倍数ではないためです。入力が1バイトまたは2バイト不足している場合、エンコーダは出力に=文字を追加して、結果が常に4文字の倍数になるようにします。
Input length (mod 3) Padding Example
─────────────────────────────────────────
0 (multiple of 3) none "Man" → "TWFu"
1 == "M" → "TQ=="
2 = "Ma" → "TWE="
一部のエンコーダーやプロトコルはパディングを削除してバイト数を節約します。JWTもこれを行います — JWT内のBase64URLエンコーディングにはパディングがまったくありません。JWTから手動でBase64をデコードする場合、一部のデコーダーが受け入れる前にパディングを追加する必要があるかもしれません。
// JavaScript: add padding back to an unpadded Base64 string
function pad(b64) {
const remainder = b64.length % 4;
return remainder ? b64 + '='.repeat(4 - remainder) : b64;
}
Base64とBase64URL — Webにとって重要なバリアント
標準のBase64は、62番目と63番目の文字として+と/を使用します。これらはどちらもURL内で特別な意味を持ちます。+はクエリ文字列内で「スペース」を意味し、/はパス区切り文字です。標準のBase64を追加エンコードなしでURLに含めると、問題が発生します。
Base64URL(RFC 4648で定義)は、これらの文字を入れ替えることでこの問題を解決します。+は-、および / は _ になります。また、通常はパディングを省略します。結果は、URL、ファイル名、HTTPヘッダーに直接入れても安全です。
Standard Base64: "abc/d+ef=="
Base64URL: "abc_d-ef"
// Convert one to the other
const toUrlSafe = (b64) => b64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
const fromUrlSafe = (b64u) => {
const b64 = b64u.replace(/-/g, '+').replace(/_/g, '/');
return pad(b64); // add padding back
};
JWTはBase64URLを使用します。最近のトークンフォーマット、OAuth stateパラメータ、およびURL内を移動するその他のものも同様です。
JavaScriptでのエンコードとデコード
JavaScriptには2つの組み込み関数があります:btoa() (バイナリからASCIIへ、エンコード) と atob() (ASCIIからバイナリへ、デコード)。名前は紛らわしいです — 任意のバイナリデータに対して期待するように動作しません。
// Simple ASCII strings — these work
btoa("Hello, world!");
// → "SGVsbG8sIHdvcmxkIQ=="
atob("SGVsbG8sIHdvcmxkIQ==");
// → "Hello, world!"
// Unicode strings — this BREAKS
btoa("héllo");
// → DOMException: invalid character
// Correct way for Unicode: encode to UTF-8 first
function utf8ToBase64(str) {
return btoa(unescape(encodeURIComponent(str)));
}
function base64ToUtf8(b64) {
return decodeURIComponent(escape(atob(b64)));
}
utf8ToBase64("héllo"); // → "aMOpbGxv"
base64ToUtf8("aMOpbGxv"); // → "héllo"
// Modern alternative (Node 16+, modern browsers)
const bytes = new TextEncoder().encode("héllo");
const b64 = btoa(String.fromCharCode(...bytes));
ファイルアップロードのようなバイナリデータの場合、ArrayBuffer または Uint8Array を使用してください:
// Convert a file to Base64 (browser)
async function fileToBase64(file) {
const buffer = await file.arrayBuffer();
const bytes = new Uint8Array(buffer);
let binary = '';
for (const byte of bytes) binary += String.fromCharCode(byte);
return btoa(binary);
}
// FileReader alternative — gives you a data URL
function fileToDataUrl(file) {
return new Promise(resolve => {
const reader = new FileReader();
reader.onload = () => resolve(reader.result);
reader.readAsDataURL(file);
});
}
Pythonでのエンコーディングとデコード
import base64
# Encode a string
encoded = base64.b64encode(b"Hello, world!")
# → b"SGVsbG8sIHdvcmxkIQ=="
# Decode
decoded = base64.b64decode(b"SGVsbG8sIHdvcmxkIQ==")
# → b"Hello, world!"
# URL-safe variant — for JWTs, URLs, filenames
url_safe = base64.urlsafe_b64encode(b"data with /and+chars")
# → b"ZGF0YSB3aXRoIC9hbmQrY2hhcnM="
# Encode a file
with open("photo.jpg", "rb") as f:
encoded_file = base64.b64encode(f.read()).decode("ascii")
コマンドラインでのエンコーディングとデコード
# macOS and Linux — encode
echo -n "Hello, world!" | base64
# → SGVsbG8sIHdvcmxkIQ==
# Decode
echo "SGVsbG8sIHdvcmxkIQ==" | base64 -d
# → Hello, world!
# Encode a file
base64 photo.jpg > photo.txt
# Decode a file
base64 -d photo.txt > photo.jpg
# Watch out — many systems wrap output at 76 characters by default
# Use -w 0 (GNU) or no flag (BSD) to disable wrapping
echo -n "long content..." | base64 -w 0
SQLでのエンコーディングとデコード
-- PostgreSQL
SELECT encode('Hello, world!'::bytea, 'base64');
-- → SGVsbG8sIHdvcmxkIQ==
SELECT convert_from(decode('SGVsbG8sIHdvcmxkIQ==', 'base64'), 'UTF8');
-- → Hello, world!
-- MySQL 8+
SELECT TO_BASE64('Hello, world!');
-- → SGVsbG8sIHdvcmxkIQ==
SELECT FROM_BASE64('SGVsbG8sIHdvcmxkIQ==');
-- → Hello, world!
よくあるバグとその回避方法
改行の罠。 一部の実装(特にMIMEやOpenSSL)では、Base64出力を64文字または76文字ごとに改行で折り返します。一方、改行を含む入力を拒否する実装もあります。正しいBase64に見えるものをデコード中に「無効な文字」エラーが出る場合は、まず空白を除去してください。
パディングの不一致。 JWTとURLセーフなBase64は通常パディングを省略します。多くのデコーダーはそれを必要とします。デコードに失敗した場合、いくつ = 文字を追加するかを計算してください: (4 - (length % 4)) % 4 そのうちの。
UTF-8の仮定。 Base64はバイトをエンコードするものであり、文字をエンコードするものではありません。文字列をエンコードするには、その文字エンコーディングが何であるかを知っている必要があります。常にエンコーディングを明示的に指定し(UTF-8がほとんどの場合正しい選択です)、結果を文字列として扱う前にバイトにデコードし直してください。
サイズの驚き。 Base64はペイロードサイズを33%増加させます。小さなアセットの場合は問題になりません。JSONに埋め込まれた10MBのファイルの場合は影響があります。ワイヤー上で13.3MBを送信することになります。大きなファイルの場合はマルチパートアップロードを推奨します。
それを秘密として扱います。 二度言う価値がある: Base64は暗号化ではない。パスワード、APIキー、その他の機密データをBase64として保存し、隠蔽できると期待してはいけない。エンコードされた文字列が見えれば、元の内容も見える。
私はWilliamです。DevCrate(DevCrate)の開発者です。Base64ツール が存在するのは、不規則な文字列を怪しいオンラインコンバーターに入れて中身を確認するのに飽きたからです。標準とURLセーフの両方のバリアントをエンコード・デコードし、ファイルを処理し、あなたのマシンから1バイトも送信しません。
このガイドでカバーされていないBase64のケースがあれば、コメントに残してください — すべて読んでいます。












