【入門編】 JWTのヘッダー・ペイロード・署名の構造とBase64Urlエンコーディング – Web APIアーキテクチャ・データ連携実践ガイド

こんにちは!ネットワークの裏側やWeb APIの美しさにロマンを感じるインフラエンジニアの皆さん、そして日々奮闘されている初学者の皆さん。

今回は、現代のWebシステムやAPI連携において欠かせない主役、「JWT(JSON Web Token)」の深い内側に迫ります。

「APIってなんだか難しそう…」「JWTの文字列、なんだか暗号みたいで怖い…」そう思っていませんか?大丈夫です。一歩ずつ、身近な例えを交えながら優しく紐解いていきましょう!

—

1. そもそもJWTってなんだろう?(現実世界の「身分証明書」に例えてみよう)

Webの世界では、「私は〇〇会社の誰々です」という証明を、サーバーとクライアントの間で何度もやり取りする必要があります。毎回「パスワードを教えてください」と確認するのは、セキュリティ的にも効率の面でもナンセンスですよね。

そこで登場するのが、JWTという名の「デジタル身分証明書(パスポート)」です。

例えば、あなたが海外旅行に行くとき、パスポートには顔写真や名前、有効期限が書かれていますよね。さらに、そのパスポートが偽物ではないことを証明するために、政府の公印やホログラムが押されています。

JWTもこれとまったく同じです。
サーバーは、ユーザーがログインしたときに「この人はこういう権限を持っていますよ」という情報をまとめたパスポート(JWT)を発行します。ユーザーは次のリクエストから、そのパスポートをサーバーに見せるだけで、スムーズにVIPルーム(保護されたAPI)に入れるようになるのです。

このJWTの正体は、実はただの文字列です。よく見ると、ドット(.)で3つのパーツに区切られています。

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

なんだか暗号のように見えますが、実はこれ、きれいに3つの部屋に分かれたお弁当箱のような構造をしているんです。中身を覗いてみましょう!

—

2. JWTを構成する「3つのお部屋」

JWTの文字列は、ドット(.)で区切られた以下の3つのセクションでできています。

1. Header(ヘッダー):「この身分証明書はどういうルールで作られたか」のラベル
2. Payload(ペイロード):「誰の、どんな情報が書かれているか」の中身(データ)
3. Signature(シグネチャ):「これが絶対に偽物ではない」という証明(署名)

それぞれを詳しく見ていきましょう。

① Header(ヘッダー):使っている道具の宣言

ヘッダーには、このJWTが「何のアルゴリズムを使って署名されているか」というメタデータ(情報についての情報)が入っています。

{
  "alg": "HS256", // 署名に使っているアルゴリズム(後で詳しく解説します!)
  "typ": "JWT"    // トークンの種類(常にJWTです)
}

② Payload(ペイロード):伝えたいメッセージ

ここが実際のデータ置き場です。誰がログインしているのか(ユーザーID)や、いつまでこの証明書が有効か(有効期限)といった情報がJSON形式で詰め込まれています。

{
  "sub": "1234567890",       // ユーザーの識別子(サブジェクト)
  "name": "山田 太郎",        // ユーザーの名前
  "admin": true,              // 管理者権限を持っているか
  "exp": 1735689600           // 有効期限(UNIX時間)
}

③ Signature(シグネチャ):絶対に改ざんさせない「封蝋(ふうろう)」

中身(ヘッダーとペイロード)が書き換えられていないことを保証するのがシグネチャです。
中世のヨーロッパで、手紙の封筒に王家の紋章が入ったロウ(封蝋)を垂らし、途中で開けられていないことを証明したのと同じ仕組みです。

ヘッダーとペイロードを合わせ、秘密の合言葉(シークレットキー)を使って計算(ハッシュ化)したものが、このシグネチャになります。もし悪意ある第三者がペイロードの「admin: false」を「admin: true」にこっそり書き換えたとしても、シグネチャの計算が合わなくなるため、サーバー側で「おや、この手紙は途中でいじられているぞ!」と一発でバレる仕組みになっています。

—

3. ちょっと待って!「暗号化」と「署名」はどう違うの?

ここで、よくある誤解を一つ解いておきましょう。
「JWTは暗号化されているから中身を見られない」というのは間違いです。

実は、ヘッダーとペイロードの正体は、ただの「Base64Url」という方式で文字をエンコード(変換)しただけのものであり、暗号化はされていません。 誰でも専用のツールを使えば、ペイロードの中身を簡単に元のJSONに戻して読むことができます。

「じゃあプライベートな情報(パスワードなど)を入れても安全なの?」
答えは「絶対にNG」です。JWTのペイロードには、パスワードや機密性の高い個人情報は決して入れないでください。あくまで「公開されても問題ないけれど、改ざんされては困る情報(誰がログインしているか等)」を載せるためのものです。

—

4. セキュリティの要:署名アルゴリズム(HS256 vs RS256)の選び方

JWTの安全性を大きく左右するのが、ヘッダーで指定する署名アルゴリズムです。代表的な2つを見ていきましょう。

HS256 (HMAC with SHA-256)

  • 仕組み: 発行するサーバーも、検証するサーバーも、「まったく同じ秘密の合言葉(シークレットキー)」を共有して署名・確認を行います。
  • メリット: 処理が非常に軽量で、設定がシンプルです。
  • デメリット: 合言葉を知っているサーバーが複数ある場合、もし1台のサーバーがハッキングされて合言葉が漏洩すると、すべてのサーバーで偽のJWTが作り放題になってしまいます。

RS256 (RSA Signature with SHA-256)

  • 仕組み: 「秘密鍵(プライベートキー)」で署名し、「公開鍵(パブリックキー)」で検証するという、非対称暗号の仕組みを使います。
  • メリット: 署名を作る権限は秘密鍵を持つ大元のサーバーだけに絞り、APIを受け取る側のサーバーは公開鍵だけを持って「検証(お墨付きのチェック)」だけを行います。そのため、検証側サーバーが万が一侵入されても、偽のトークンを作られるリスクを防げます。
  • デメリット: HS256に比べて処理に少しCPUパワーを消費します。

【現場での選び方のコツ】
自社で完結する小さなシステムであれば、お手軽な HS256 で十分スタートできます。しかし、マイクロサービスアーキテクチャのように、多くの独立したAPIサーバーが連携するモダンな環境であれば、セキュリティの担保がしやすい RS256 を選択するのがプロの現場の定石です。

—

5. 実践!PythonでJWTの仕組みを覗いてみよう

百聞は一見にしかず。Pythonの定番ライブラリ PyJWT を使って、実際にJWTがどう作られ、どう検証されるのかコードで見てみましょう。

import jwt
import time

# サーバーだけが知っている秘密の合言葉(HS256の場合)
SECRET_KEY = "super-secret-key-don't-tell-anyone"

# 1. ペイロード(伝えたい情報)の作成
payload = {
    "sub": "user_001",
    "name": "インフラ 太郎",
    "iat": int(time.time()),                  # 発行時刻 (Issued At)
    "exp": int(time.time()) + 3600            # 有効期限(1時間後)
}

# 2. JWTの生成(エンコード)
# ヘッダーとペイロードを結合し、シークレットキーで署名を作ります
token = jwt.encode(payload, SECRET_KEY, algorithm="HS256")

print("--- 生成されたJWT ---")
print(token)
print("\n")

# 3. JWTの検証と中身の取り出し(デコード)
try:
    # 署名が正しいか、有効期限が切れていないかを自動でチェックします
    decoded_payload = jwt.decode(token, SECRET_KEY, algorithms=["HS256"])
    print("--- 検証成功!ペイロードの中身 ---")
    print(decoded_payload)

except jwt.ExpiredSignatureError:
    print("エラー: トークンの有効期限が切れています。")
except jwt.InvalidTokenError:
    print("エラー: 不正なトークン(または改ざんされています)。")

このコードを実行すると、先ほど紹介したドット区切りの美しいJWT文字列が生成され、正しく合言葉が一致すれば中のデータが安全に取り出せる様子が確認できます。

—

まとめ

今回は、JWTの3つの構造(Header, Payload, Signature)と、それが支えるセキュリティの仕組みについて紐解いてきました。

  • JWTはWebの世界の「改ざん防止機能付きのデジタル身分証明書」である。
  • 中身(Payload)は暗号化されているわけではなく、誰でも読めるので機密情報は入れてはいけない。
  • システムの規模やセキュリティ要件に合わせて、HS256やRS256といった署名アルゴリズムを適切に使い分ける必要がある。

ネットワークやAPIの背後にあるこうしたルールを一つずつ理解していくと、日々のインフラ構築やアプリケーション開発が何倍も楽しく、そして確実なものになっていきます。

それでは、また次回の深淵なプロトコルの世界でお会いしましょう!

コメント

タイトルとURLをコピーしました