こんにちは!ネットワークの裏側や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の背後にあるこうしたルールを一つずつ理解していくと、日々のインフラ構築やアプリケーション開発が何倍も楽しく、そして確実なものになっていきます。
それでは、また次回の深淵なプロトコルの世界でお会いしましょう!
コメント