手を振るまもるくんゆるふわサイバーセキュリティ
考え中のまもるくん

JWTをPythonでゼロからつくる|ログイン認証トークンのしくみ

2026-09-12実践

#JWT#認証#トークン#Python#実践

ログイン状態を保つ仕組みとして、いまや定番の JWT(JSON Web Token)。この記事では中身をブラックボックスにせず、Pythonの標準ライブラリだけでゼロから実装します。作ってみると「なぜ改ざんできないのか」がはっきりわかります。

JWTの3つのパーツ

JWTは ヘッダ.ペイロード.署名 の3つを.で繋いだ文字列です。

3パーツをドットで連結

🏷️

ヘッダ

署名方式など

📦

ペイロード

ユーザーID等

✍️

署名

改ざん検知

準備

標準ライブラリ(hmachashlibbase64json)だけ。

① JWTを発行する

ヘッダとペイロードをBase64URLで符号化し、秘密鍵でHMAC署名します。

import hmac, hashlib, base64, json

SECRET = b"my-server-secret"

def b64(data: bytes) -> str:
    return base64.urlsafe_b64encode(data).rstrip(b"=").decode()

def make_jwt(payload: dict) -> str:
    header = {"alg": "HS256", "typ": "JWT"}
    h = b64(json.dumps(header).encode())
    p = b64(json.dumps(payload).encode())
    signing_input = f"{h}.{p}".encode()
    sig = hmac.new(SECRET, signing_input, hashlib.sha256).digest()
    return f"{h}.{p}.{b64(sig)}"

token = make_jwt({"user_id": 42, "role": "admin"})
print(token)

② 検証する(改ざん検知)

同じ手順で署名を作り直し、一致するか確かめます。

def verify_jwt(token: str):
    h, p, s = token.split(".")
    expected = hmac.new(SECRET, f"{h}.{p}".encode(), hashlib.sha256).digest()
    if not hmac.compare_digest(b64(expected), s):   # タイミング攻撃対策
        return None
    pad = "=" * (-len(p) % 4)
    return json.loads(base64.urlsafe_b64decode(p + pad))

print("正規:", verify_jwt(token))

# ペイロードを role=admin に改ざんしてみる
h, p, s = token.split(".")
fake_p = b64(json.dumps({"user_id": 42, "role": "superadmin"}).encode())
print("改ざん:", verify_jwt(f"{h}.{fake_p}.{s}"))

出力は正規なら中身が返り、改ざんはNone(検証失敗)。ペイロードを書き換えても、秘密鍵を知らなければ正しい署名を作れないので即バレます。

⚠️

ペイロードは『暗号化』ではない

JWTのペイロードはBase64で誰でもデコードできます(暗号化ではない)。だからパスワードなど秘密情報は入れないこと。JWTが守るのは「改ざんされていないこと」であって「中身の秘匿」ではありません。

🌱

有効期限を必ず入れる

実務では exp(有効期限)をペイロードに入れ、検証時に期限切れを弾きます。盗まれたトークンが永久に使えるのを防ぐためです。本番では実績あるライブラリ(PyJWTなど)の利用を推奨します。

まとめ

  • JWTは ヘッダ.ペイロード.署名 の3構造
  • 署名はHMAC。秘密鍵を知らないと正しい署名を作れない=改ざん検知
  • 検証はhmac.compare_digestでタイミング攻撃を防ぐ
  • ペイロードは暗号化ではない。秘密情報は入れず、expで期限を付ける

もう少し詳しく(背景と理論)

JWT(JSON Web Token)は RFC 7519 で定義される、署名付きの自己完結型トークンです。ヘッダ・ペイロード・署名の3部をドット区切りでBase64URLエンコードします1。最も有名な脆弱性が alg: none 攻撃——署名アルゴリズムを「なし」に改ざんして検証を無効化する手口で、検証側は許可アルゴリズムを固定してこれを防ぎます2。また対称鍵(HS256)と公開鍵(RS256)のアルゴリズム取り違え攻撃にも注意が要ります。ペイロードは暗号化されず誰でも読めるため、パスワード等の秘密は入れないこと、exp(有効期限)を必ず設定すること、失効はサーバー側の管理が必要なことが実務の鉄則です3

次の一歩 🌸

署名の基礎はHMACで署名・検証、パスワード保存はパスワードハッシュ、多要素認証はMFAへどうぞ。

Footnotes

  1. RFC 7519 "JSON Web Token (JWT)." 署名は JWS(RFC 7515)で規定。header.payload.signature を Base64URL で連結する。

  2. alg:none を受理する実装は署名検証を回避される。検証時は許可アルゴリズムをサーバー側で固定し、HS/RS の取り違えも防ぐ。

  3. ペイロードは暗号化されず Base64 デコードで読める。秘密情報を入れない。exp で短寿命にし、失効はブラックリスト等で別途管理する。

🔥 この分野の最新トレンドをチェック →

あわせて読みたい