レッスン 6
よくある Base64 のミス
アルファベットの取り違え、改行、UTF-8 テキストの誤デコード。
Base64 の落とし穴は 4 テーマに集約されます: アルファベット不一致、空白の驚き、二重エンコード、UTF-8 テキスト vs 生バイトの誤処理。
アルファベットの混乱
症状:
-/_(URL-safe)と+//(標準)が混在すると断続的デコード失敗- 仕様が Base64URL を期待する場所に
+や/が残る JWT 風断片
対処: 変換を集中化; 正規サンプル(パディング付き MIME、パディングなし URL-safe ベクトル)のラウンドトリップをユニットテスト。
サービス全体に regex「修正」を散らさない — いずれかのパスが trim 忘れや誤正規化をします。
大文字小文字の癖
アルファベットの A–Z vs a–z セグメントインデックスは大文字小文字が重要; payload 全体に誤って .toLowerCase() すると情報が破壊されます。
残存空白と改行
PDF/メールからのコピーは stray スペースとソフト改行を注入しがち。
戦略:
- 仕様が許すときだけ
ignoreWhitespaceフラグでデコード - PEM パースは header/footer 行を除去 — 内部の任意空白は信頼できない
- ログパイプラインがレコード分割 — 疑わしく短い断片を拒否
不可視 Unicode 空白(narrow no-break space、BOM)はバグとして扱い、明示許可リストで早期正規化。
URL デコード順序バグ
percent デコードを二重適用したり Base64 正規化と順序を入れ替えるとゴミバイト — 特に %2B、%2F、%3D(+、/、= 相当)。
演習: 複数プロキシを通るユーザー提出トークン — フレームワークがスペースを書き換える前の生クエリを捕捉。
意図しない二重エンコード
誰かが資格情報 JSON を Base64 エンコード、文字列を受け取り、誤って再び Base64 — DB に保存された成果物はどの当事者の想定とも合わない。
コードで命名(encodeOnce、層責任を明確化)し、アサーションログは秘密を漏らさず長さ + 先頭数文字のハッシュを出力してフォレンジック diff に。
UTF-8 テキストの混乱
「中国語文字列を Base64 したらおかしい」 — よくある失敗は層の取り違え: UTF-8 バイトをエンコードしたのに別 charset でデコード、または同一論理テキストの別正規化と比較。
言語のヘルパーでパイプラインを明示: Unicode 文字列 → UTF-8 バイト → Base64 テキスト、デコード時は逆。
レガシー単バイトデフォルトを仮定しない — プラットフォームコードページはデコード後に文字化けを生みがち。
JSON payload
JSON は UTF-8(または文書化されたエスケープ重視の代替)を要求。サーバー正規化 vs BOM 付き pretty-print 差分ではなく、シリアライズ済み JSON バイトをエンコード。
DB の text vs binary 列
Base64 デコード protobuf を TEXT 型列に照合順序変換で保存すると微妙に破損 — 不適切だが ORM 型誤ラベルで観察されます。
セキュリティ脚注
Base64 blob は素人目には不透明だが機密ではない。Base64 だけで秘密を運ぶのは信頼できない輸送上の平文と同等。
署名と MAC は正規バイトレイアウトで動作 — パディング形式や大文字小文字を変えると静かに検証失敗。
定数時間の落とし穴
稀だが現実: Base64 由来秘密の素朴な文字列等価比較 vs タイミング攻撃 — 生トークン扱いでは crypto ライブラリの安全 compare を優先 — Base64 固有ではないが隣接。
要点
相互運用はチームが次に合意するとき勝ちます。
- アルファベットとパディングルール
- デコード前正規化(改行/URL ステップ)
- 内容がテキスト(UTF-8)か不透明バイトか
- 文書化プロトコル層なしの再帰エンコード禁止
CI にゴールデンベクトルを置き早期に回帰を捕捉。