JSON 内の Base64 フィールドをデコードする方法
- 入力 · JSON に JSON を貼り付けるか、
.jsonや.harファイルをドロップします。 - 表には、見つかったものすべてが パス、推定形式、確度、デコード結果 のプレビュー付きで並び、デコード結果をコピー と ダウンロード のボタンもあります。
- 出力欄には、テキスト、JSON、JWT の値をその場でデコードした文書全体が入るので、そのまま読んだり差分を取ったりできます。
- 短い文字列を飛ばすには 最小の長さ(デフォルト 8)を調整し、最初の階層で止めるには 入れ子の JSON をパース のチェックを外し、短いバイナリの鍵を探すときは 確度の低い候補も表示 にチェックを入れます。
JSON を Base64 に タブはその逆を行います。JSON を検証し、入力どおり、圧縮(minify)、整形のいずれかの形でエンコードします。URLセーフ、パディングなし、折り返しのオプションもあります。
例:3 つのエンコード済みフィールドを持つ API レスポンス
{
"event": { "body": "eyJvcmRlcklkIjo0MiwicXR5IjoyfQ==", "isBase64Encoded": true },
"file": { "name": "README.md", "encoding": "base64",
"content": "IyBEZW1vCgpIZWxsbyBmcm9tIHRoZSBSRUFETUUuCg==" },
"prefs": "eyJ0aGVtZSI6ImRhcmsifQ==",
"sha": "3b18e512dba79e4c8300dd08aeb37f8e728b8dad"
}
| パス | 推定形式 | デコード結果 |
|---|---|---|
$.event.body | JSON | {"orderId":42,"qty":2} |
$.file.content | テキスト | # Demo / Hello from the README. |
$.prefs | JSON | {"theme":"dark"} |
$.sha は表示されません。40 文字の16進数の文字列は、アルファベットだけ見れば有効な Base64 ですが、これは Git のハッシュで、スキャナーは長い16進数の文字列を意図的に除外しています。表にある eyJ という接頭辞はどれも {" の Base64 で、エンコードされた JSON をすぐに見分ける目印です。
JSON の中で Base64 が潜んでいる場所
- AWS API Gateway と Lambda のイベントは、バイナリや圧縮された本文を
"isBase64Encoded": true付きのbodyで運びます。 - GitHub の contents API は、ファイルを
"encoding": "base64"付きのcontentとして返し、\nで行に分割しています。ここでは改行は無視されます。 - Gmail API のメッセージパーツは、
body.dataに URLセーフな Base64 を使います。URLセーフな入力(-と_)は自動で検出されます。 - JWT:
access_tokenやid_tokenのフィールドにあるものは、ヘッダーとペイロードがデコードされます。署名の検証には JWT デコーダー を使ってください。 - Data URI:
avatarやlogoのフィールドにあるdata:image/png;base64,…などは、MIME タイプ付きで認識されます。 - Kubernetes の Secret の JSON 形式。Kubernetes Secret デコーダー には Secret 専用の機能があります。
Python でやってみる
UTF-8 のテキストにデコードできる文字列を報告する、最小限の走査処理です。
import base64, binascii, json, sys
def walk(node, path="$"):
if isinstance(node, dict):
for k, v in node.items():
yield from walk(v, f"{path}.{k}")
elif isinstance(node, list):
for i, v in enumerate(node):
yield from walk(v, f"{path}[{i}]")
elif isinstance(node, str) and len(node) >= 8:
try:
text = base64.b64decode(node, validate=True).decode("utf-8")
yield path, text
except (binascii.Error, UnicodeDecodeError):
pass
for path, text in walk(json.load(open(sys.argv[1]))):
print(path, "=>", text[:60])
これでは URLセーフやパディングなしの値、画像などのバイナリのペイロードを見逃します。実際のスキャナーの作業の大半はそこにあります。デコードの詳細は Python の Base64 を、アルファベットの違いは Base64 と Base64URL の違い をご覧ください。
制限
- 検出はヒューリスティックです。8 文字未満の値や、ランダムに見えるバイナリの鍵は、見逃されるか「不確か」とされることがあります。それらを見るには 最小の長さ を下げ、確度の低い候補を表示してください。
- スキャンは 200,000 個の文字列で止まり、表示するのは最大 1,000 行です。これで大きな HAR ファイルも、タブを固まらせずに扱えます。
- 無効な JSON は、行と列を示して報告されます。JSON にデコードされる Base64 文字列が 1 つだけなら、Base64 を JSON に変換 を使ってください。
よくある質問
Base64 と普通の文字列をどうやって見分けているのですか?
候補を 1 つずつデコードして結果を調べます。読める UTF-8、有効な JSON、既知のファイルシグネチャなら確度が高いと判断します。16進数のハッシュ、数字だけの文字列、普通の単語は除外し、バイナリの結果は長さとパディングに応じて「可能性大」か「不確か」として示します。
HAR ファイル内の Base64 フィールドをデコードできますか?
できます。ブラウザのネットワークパネルから書き出した .har をドロップしてください。"encoding": "base64" で保存されたレスポンス本文が、リクエストとレスポンスの JSON 内の Base64 と一緒に、デコードした内容付きで表に表示されます。
画像などのバイナリの値はどうなりますか?
検出したファイル形式とダウンロードボタン付きで一覧に表示され、出力欄では Base64 のまま残ります。その場で置き換えられるのは、テキスト、JSON、JWT の値だけです。