テクノロジー · 実用ガイド

PythonのBase64、validate=Trueでも別表記を受理?パディングビットと実行版を確認

厳格なデコードと単一の正規表記は別の確認だ。17項目のローカル対照で、未使用ビット、版ごとの引数、長さ制限、デコード後のバイトの意味を分ける。

実測した二組のBase64表記と二進数の未使用ビットを示す独自技術イラスト。
独自技術イラスト:CPython3.12.14の厳格デコードは両組を受理し、再エンコードはZg==とZm8=だけを返した。他版の実測ではない。 Watch at Ease

本誌のCPython3.12.14では、base64.b64decode(value,validate=True)がZg==とZh==をともにバイトfへ、Zm8=とZm9=をともにfoへデコードした。厳格デコードの成功だけでは、入力文字列が正規表記かどうかは分からない。

まず必要なプロトコルを決めよう。本稿が試すのは、空ではないbytes入力、標準Base64アルファベット、必要なパディング、長さ制限、再エンコードの完全一致という限定的な方針だ。JWT、署名、MIMEメッセージは検証しない。

1. パディング文字と未使用ビットを分ける

実測したZg==とZh==は等号の数が同じで、違いは最後のアルファベット文字の未使用ビットにある。厳格デコードは両方を受理したが、返されたバイトを再エンコードするとZg==だけになり、後者は一致検査に失敗した。Zm8=とZm9=でも同じ結果だった。

RFC4648は適合するエンコーダーに未使用のパディングビットをゼロにするよう求める。デコーダーは非ゼロのビットを拒否してよく、参照元プロトコルがさらに厳格な要件を決められる。受理されただけでアプリの単一表記規則に適合するとは限らない。

2. 新しい引数を使う前に実行版を確認

Python3.15の文書には非ゼロのパディングビットを拒否するcanonical=Trueが追加された。アルファベット検査もvalidate=Trueで明示し、プロトコルのパディング・サイズ規則を維持する。本誌は文書を読んだがPython3.15を実行していない。

実際のCPython3.12.14でcanonical=Trueを渡すと、未知のキーワード引数としてTypeErrorになった。この環境ではvalidate=Trueでデコードし、本稿の標準パディング方針としてbase64.b64encode(decoded)==encodedを要求する。この比較は表記の検査であり、MACや署名の検証ではない。

3. 制限付き方針を最後まで適用する

補助関数は入力型が正確にbytesであることを要求し、4096バイトを超える符号化入力を拒否する。厳格デコード後、3072バイトを超える出力を拒否し、空ではないというアプリの規則と標準再エンコードの一致を検査する。すべて通過してからバイトを返す。

17項目にはf、fo、fooの正しい符号化、二つの未使用ビット違い、余分なパディング、改行、必要なパディングの欠落、URL用文字、パディング後の追加データ、空入力が含まれる。追加の対照ではデコード前後の長さ制限、未対応の引数、独立したUTF-8失敗を確認した。

4. 形式と内容の意味も別々に確認

完全な3バイトfooの正規表記は等号なしのZm9vだ。必要なパディングを求めることは、全入力に=を足す意味ではない。実測の厳格デコーダーはZm9v=を拒否した。空のBase64はデコードできたが、本アプリは空のペイロードを意図的に拒否した。

正規入力/w==はバイト0xffになり、表記方針を通過したが、UTF-8としてのデコードは失敗した。形式の正しさは文字列やファイルの妥当性、真正性を証明しない。診断用に失敗した元入力を保持し、厳密な形式を求める契約で文字削除やパディング追加を黙って行わないことが大切だ。

入力長、厳格デコード、ペイロード規則、再エンコード一致の四段階を示す独自イラスト。
独自技術イラスト:bytes、入力上限4096、出力上限3072バイト、空不可は本例の方針。Python3.15の引数は文書確認のみ。 Watch at Ease