エンコード・セキュリティ

Base64 は暗号化ではない:本来の用途と、秘密を守りたいときに使うもの

Base64 はバイト列をテキストに変え、テキスト前提のシステムを通れるようにする仕組みです。誰でも関数 1 回で元に戻せます。使うべき場面(メール、JSON、data URL)、33% の増加、エンコード・ハッシュ・暗号化の違い。

要点

Base64 は、任意のバイト列を 64 種類の安全な文字(A–Z、a–z、0–9、+、/)だけで書き表す方法です。画像、PDF、鍵といったバイナリデータを、テキストしか扱えないシステム(メール本文、JSON の文字列、URL、HTML の属性)に通すために存在します。これはエンコードであって暗号化ではありません。鍵はなく、デコードはどの言語にも、どのブラウザの開発者コンソールにもある関数を 1 回呼ぶだけです。「Base64 で」保存されたパスワードは、手間を一つ増やしただけの平文です。

なぜ存在するのか

メールは 1970 年代に 7 ビット ASCII 向けに設計されました。添付ファイルが登場したとき(MIME、1992 年)、JPEG のバイト列は 256 通りの値をすべて使い、その中にはメールサーバーにとって「行末」や「メッセージ終了」を意味する値も含まれていたため、無害なテキストに偽装する必要がありました。その答えが Base64 です。3 バイト(24 ビット)を取り、6 ビットずつ 4 つに分け、それぞれを 64 文字のどれかに対応させます。3 バイトが 4 文字になる。これが有名な 33% のオーバーヘッドで、3 MB の添付ファイルは 4 MB のメールになります。「25 MB」の上限に収まるファイルが 18 MB なのはこのためです。

同じ手法は、テキストしか通らない場所ならどこにでも現れます。小さな画像を Web ページに直接埋め込む(data:image/png;base64,…)、HTTP ヘッダーにバイナリのトークンを入れる(Authorization: Basic …)、PEM ファイルで証明書や鍵を運ぶ、JSON のフィールドにバイト配列を詰め込む、といった場面です。

つまずきやすいバリエーション

  • 標準形式と URL セーフ形式。 標準の Base64 は + と / を使いますが、どちらも URL の中では特別な意味を持ちます。URL セーフのアルファベット(RFC 4648 §5)はこれを - と _ に置き換えます。一方の形式で作ったトークンをもう一方としてデコードすると、この 2 文字で失敗します。JWT は URL セーフ形式です。
  • パディング。 出力の長さは常に 4 の倍数で、足りない分は = で埋めます。パディングを省く生成側もあれば(これも JWT)、パディングを必須とするデコーダーもあります。ほかに問題のない文字列でデコードが失敗したら、長さが 4 で割り切れるまで = を足してみてください。
  • 改行。 MIME は 76 文字、PEM は 64 文字で折り返します。デコーダーの多くは空白を無視しますが、すべてではありません。
  • 元になる文字コード。 Base64 がエンコードするのはバイトです。文字列を Base64 にするには先にバイト列に変換する必要があり、UTF-8、UTF-16、Latin-1 のどれを選ぶかで結果が変わります。JavaScript の定番バグ、btoa("é") が例外を投げる現象はまさにこれで、btoa は Latin-1 しか受け付けません。先に UTF-8 のバイト列にエンコードしてください。

Base64 変換は両方のアルファベット、パディング、改行、UTF-8 に対応し、テキストとしても、ダウンロード可能なファイルとしてもデコードできます。data: URL やメールの添付ファイルを、ブラウザの中で元のファイルに戻せます。

エンコード、ハッシュ、暗号化

この 3 つの言葉はくだけた文章では混同されがちですが、意味はまったく異なります。

元に戻せるか 鍵が必要か 目的
エンコード(Base64、16 進、URL エンコード) はい、誰でも いいえ データを伝送路に合わせる
ハッシュ(SHA-256、MD5) いいえ いいえ データの指紋を取り、改変されていないか確かめる
暗号化(AES、RSA) はい、鍵があれば はい 鍵を持たない人からデータを秘匿する

ファイルのハッシュを使えば、ダウンロードしたものが配布元の公開したものと一致するかを確認できます。ハッシュ計算はブラウザ内で MD5、SHA-1、SHA-256/384/512 を計算し、貼り付けたチェックサムと照合します。ただし何かを隠すわけではなく、ファイルはファイルのままです。3 つのうち秘匿性を提供するのは暗号化だけで、その強さは鍵の強さで決まります。そこで必要になるのが十分にランダムなパスワードです。

秘密情報を Base64 にしようとしているなら

やめてください。具体的には次のとおりです。

  • Base64 のパスワードを書いた設定ファイル(古い Java や .NET のアプリでよく見るパターン)は、ファイルを開いた人にとっては平文のパスワードです。
  • フロントエンドの JavaScript に「難読化」して置いた API キーは、Base64 であろうとなかろうと、ネットワークタブで丸見えです。
  • Basic 認証を素の HTTP で使うと、ユーザー名とパスワードが Base64 エンコードされた状態、つまり平文で送られます。許容できるのは、通信路が暗号化を担う HTTPS の中だけです。

データを保存または送信し、なおかつ秘密にしておく必要があるなら、本物の暗号(プラットフォームの暗号ライブラリ経由の AES-256-GCM)で暗号化し、そのうえでテキストの伝送路を通す必要があれば暗号文を Base64 にします。暗号化のあとにエンコードするのは問題ありません。誤りなのは、暗号化の代わりにエンコードすることです。

テキスト読み上げTextToSpeech.tools 動画圧縮FreeCompress.video 中英辞典ChineseDict.com