Base64エンコーディングとは何ですか?わかりやすい英語のガイド (および暗号化ではない理由)
見たことがあるでしょう。文字と数字の長い文字列。おそらく 1 つまたは 2 つの等号で終わり、JWT、電子メール ソース、またはイメージ タグに存在します。それが Base64 であり、コンピューティングで最も一般的なエンコーディングの 1 つであり、驚くほど多くの開発者が、実際に何をするのか知らずに、あるいはさらに悪いことに、実際に行われないことを行うと信じて毎日使用しています。このガイドでは、Base64 について、わかりやすく説明します。Base64 とは何か、なぜ存在するのか、どこで遭遇するのか、そして実際のセキュリティ インシデントを引き起こす 1 つの危険な誤解について説明します。
Base64 とは実際には何ですか
Base64 は、64 個の印刷可能なテキスト文字 (26 個の大文字、26 個の小文字、10 桁の数字、および 2 個の記号、プラス (+) とスラッシュ (/)) のみを使用して、任意のバイトのバイナリ データを表す方法です。等号 (=) は末尾のパディングとして使用されます。それがアルファベット全体であり、名前の由来です。 Base64 出力のすべての文字は、制御コードや曖昧な空白を含まない安全で印刷可能な文字であり、これがまさに重要です。
それが存在する理由は歴史的であり、今でも意味があります。インターネットのコア プロトコルである SMTP 経由の電子メール、HTTP ヘッダーなどは、プレーン テキスト用に設計されています。画像や暗号化された BLOB などの生のバイナリ データをフィードすると、特定のバイト値が制御文字として誤って解釈され、データが破損します。 Base64 は、バイナリを、テキストベースのチャネルがそのまま残るテキストのサブセットに変換することで、この問題を解決します。これはバイナリの世界とテキストの世界の間の翻訳者です。
仕組みを簡単に説明すると、
アルゴリズムは入力を一度に 3 バイト受け取ります。 3 バイトは 24 ビットで、それぞれ 6 ビットの 4 つのグループに分割され、各 6 ビット グループは 64 文字の 1 つにマップされます。したがって、入力の 3 バイトごとがちょうど 4 文字の出力になります。入力が 3 バイトのきれいな倍数ではない場合、Base64 は出力に等号を埋め込みます (最後のグループが 2 バイトの場合は 1 ==、1 バイトのみの場合は 2 ==)。そのため、結果は常に 4 文字の倍数になります。これが、後続の等号の意味です。これらの等号は、最終グループに実際のバイトが何バイトあったかをデコーダに伝えます。
この 3 対 4 の比率は直接的な影響を及ぼします。つまり、Base64 出力は元のデータよりも約 33% 大きくなります。 1 MB の画像は、エンコードされると約 1.37 MB になります。このサイズのオーバーヘッドは、テキストの安全性のために支払う代償であり、これが、Base64 が小さなものには最適で、大きなものには不適切な選択肢である理由です。
Base64 に出会う場所
Base64 は、一度調べてしまえばどこにでもあります。データ URL は、ファイルを HTML または CSS に直接埋め込みます。data:image/png;base64 などは、イメージ タグや背景スタイルでよく見られます。これにより、小さなアイコンを別のリクエストとしてではなくページとともに読み込むことができます。電子メールの添付ファイルは Base64 でエンコードされているため、バイナリ ファイルはテキストベースのメール転送に耐えられます。これまでに送信したすべての添付ファイルはこの方法で送信されるため、生の電子メール ファイルは、送信されるファイルよりも大きくなります。
JSON Web トークン (JWT) は、ヘッダーとペイロードを URL セーフな Base64 でエンコードします。 HTTP 基本認証では、ユーザー名とパスワードがヘッダー内の Base64 として送信されます。 JSON 本文内でファイルのアップロードを受け入れる API は、JSON がテキストであり生のバイトを保持できないため、ファイルを Base64 エンコードします。また、PEM ファイル、SSL 証明書、SSH キーは、BEGIN ヘッダー行と END ヘッダー行の間にラップされた Base64 でエンコードされたバイナリです。同じ単純なエンコーディングがすべての基礎になっています。
危険な通説: Base64 は暗号化ではない
これを理解することが最も重要なことです。理解を誤ると実際のセキュリティ侵害を引き起こすからです。 Base64 はセキュリティをまったく提供しません。暗号化ではありません。エンコードされた文字列を持っている人は誰でも、ブラウザ コンソールで 1 行で、キーを使用せずに即座にそれをデコードできます。文字列 c2VjcmV0 は約 1 秒で「secret」にデコードされます。
危険性はBase64の見た目から来ています。 Base64 文字列はスクランブルされてランダムに見え、視覚的には暗号化されたデータに似ているため、人々はそれが保護されていると思い込まされます。これは本物のインシデントにつながります。開発者は、Base64 でエンコードされたデータベース認証情報を含む構成ファイルを、エンコードによって隠蔽されていると信じてバージョン管理にコミットしますが、実際はそうではありません。 API は Authorization ヘッダーをログに記録しますが、レビュー担当者は Base64 パスワードを「読み取ることができない」ため、誰かが 5 秒以内に解読するまで事実上プレーン テキストとしてログに残ります。 API キーを Base64 としてデータベースに保存することは不透明に見えますが、何も保護されません。
URL セーフな Base64 (Base64url)
標準の Base64 では + と / を使用しますが、どちらも URL では特別な意味を持ち、+ はクエリ文字列内のスペースを意味し、/ はパス セグメントを区切ります。そのため、Base64url と呼ばれる URL セーフなバリアントは、+ を - (マイナス) に、/ を _ (アンダースコア) に置き換え、通常は URL でパーセントエンコーディングが必要となる = パディングを削除します。これは、JWT、OAuth トークン、および URL セーフ Cookie が使用するバリアントです。 JWT セグメントを厳密な標準 Base64 デコーダにフィードしてエラーやガベージが発生した場合、通常はこれが理由です。最初に URL セーフな文字を変換して戻し、パディングを復元する必要があります。
Unicode の落とし穴
英語以外のテキストを Base64 エンコードする開発者には、微妙なバグが 1 つあります。古典的なブラウザ関数 btoa() は、各文字がシングル バイトであると想定しており、アクセント付き文字、絵文字、または非ラテン文字では分割されます。修正するには、最初にテキストを UTF-8 でエンコードし、次に結果のバイトを Base64 でエンコードします。そうしないと、「café」または「こんにちは」が文字化けして表示されます。優れたエンコーダーはこの UTF-8 ステップを処理するため、アクセント付きのテキストと絵文字がきれいに往復します。
いつ使用するか、いつ避けるべきか
テキストのみのチャネルを通じて小さなバイナリ データ (小さなインライン アイコン、トークン、JSON ペイロード内の小さなファイル、デバッグ中の資格情報など) を移動する必要がある場合は、Base64 を使用してください。パフォーマンス重視のパスにある大きなバイナリ ファイルの場合はこれを避けてください。33% のサイズ ペナルティと個別のキャッシュの損失を考慮すると、実際のファイルまたはマルチパート アップロードの方が良い選択となります。また、セキュリティ層としては決して使用しないでください。 Base64 をレーン、表現、トランスポート内に保持しておけば、Base64 は信頼性の高い汎用ツールになります。