ログイン後のAPI通信などで「eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk」のようなドットで区切られた長い文字列を見たことがあるかもしれません。これはJWT(JSON Web Token)と呼ばれる、認証・認可の場面で広く使われている仕組みです。この記事ではJWTの構造と、「デコードできる=改ざんできる」という誤解について解説します。
1. JWTとは何か:3部構成の文字列
JWT(JSON Web Token)は、「ヘッダー(Header)」「ペイロード(Payload)」「署名(Signature)」の3つの部分をドット(.)で連結した1本の文字列です。それぞれの部分はBase64url(URLで使っても問題ない文字だけに調整したBase64)でエンコードされており、見た目は英数字と記号が並んだ1つの長い文字列になっています。
実際にJWTの中身がどう分解されるか確認したい場合はJWTデコーダーにトークンを貼り付けてみると、3つの部分がそれぞれ何を表しているか一目で分かります。
2. 各部の役割:ヘッダー・ペイロード・署名
| 部分 | 内容 | 役割 |
|---|---|---|
| ヘッダー | 署名アルゴリズム(例:HS256)やトークンの種類 | このトークンがどう作られ、どう検証すべきかのメタ情報 |
| ペイロード | ユーザーID・有効期限・権限などのクレーム(claim) | 実際にやり取りしたい情報の本体 |
| 署名 | ヘッダーとペイロードを秘密鍵(または秘密鍵に対応する鍵)で計算した値 | 改ざんされていないことを検証するための値 |
ペイロードにはユーザーIDや権限(ロール)、有効期限などの「クレーム」と呼ばれる項目が含まれます。これらの情報を毎回データベースに問い合わせなくても、JWT自体から読み取れるようにしている点がJWTの利点です。
3. ヘッダーとペイロードは暗号化されていない
ここで重要なのが、ヘッダーとペイロードはBase64urlで「符号化」されているだけで、暗号化はされていないという点です。Base64と同じく、これは「データの表現形式を変換する」だけの仕組みであり、鍵やパスワードなしに誰でも一瞬で元のJSONに戻すことができます。つまり、JWTを見れば、ペイロードに書かれているユーザーIDや権限といった内容は誰でも読めてしまいます。
この性質上、パスワードやクレジットカード番号といった機密情報をそのままペイロードに入れるのは適切ではありません。JWTは「内容を隠す」ためのものではなく、「内容が改ざんされていないことを検証する」ためのものだと理解しておく必要があります。
4. 重要な誤解の訂正:「読める」ことと「改ざんできる」ことは別問題
「ヘッダーとペイロードがデコードできて誰でも読めるなら、書き換えるのも簡単なのでは」と思われがちですが、これは誤解です。JWTには3番目の要素として「署名(Signature)」があり、これがヘッダーとペイロードの改ざんを検知する役割を担っています。
署名は、サーバーだけが知っている秘密鍵(または秘密鍵に対応する鍵ペア)を使って、ヘッダーとペイロードの内容から計算された値です。攻撃者がペイロードの中身(例えばユーザーIDや権限)を書き換えても、その新しい内容に対応する正しい署名を、秘密鍵を持たない攻撃者は作り出せません。サーバーはトークンを受け取った際に「ヘッダー・ペイロードの内容」と「署名」が正しく対応しているかを秘密鍵を使って再計算・検証するため、内容だけ書き換えられたトークンは検証時に弾かれます。
つまり「デコードして内容を読むこと」は誰でもできますが、「検証に通る形で内容を書き換えること」は秘密鍵を知らない限りできません。この2つを混同しないことが、JWTを正しく理解する上で最も重要なポイントです。
5. JWTが使われる場面
- •ログイン後の認証情報の受け渡し:ログイン成功時にサーバーがJWTを発行し、以降のリクエストでクライアントがそれを提示する
- •APIの認可:JWTのペイロードに含まれる権限(ロール)情報を見て、そのリクエストを許可するかどうかを判断する
- •サービス間の情報伝達:マイクロサービス構成で、認証済みであることや所属情報を複数のサービス間で受け渡す
6. 有効期限(exp)の重要性
JWTのペイロードには「exp(expiration time)」というクレームを含めるのが一般的で、これはトークンがいつまで有効かを示すタイムスタンプです。万が一トークンが漏洩しても、有効期限が切れていればサーバー側で受け付けないようにできるため、被害の範囲を限定する役割を持ちます。
有効期限を長く設定しすぎると、漏洩時のリスク期間が延びてしまいます。一般的には短い有効期限のアクセス用トークンと、それを再発行するための別の仕組み(リフレッシュトークンなど)を組み合わせて運用されることが多くあります。
7. 実装時に気をつけたい「alg: none」問題
JWTの仕様上、ヘッダーの署名アルゴリズム(alg)には「none(署名なし)」という値も存在します。過去には、サーバー側の検証ライブラリがこのヘッダーの値をそのまま信用してしまい、攻撃者が「alg: none」に書き換えたトークンを送ることで署名検証そのものを迂回できてしまう、という脆弱性が複数のライブラリで報告されたことがあります。トークンを検証する側の実装では、想定しているアルゴリズム以外を許可しないようにあらかじめ固定しておくことが、安全にJWTを扱う上での基本的な対策とされています。
まとめ
JWTはヘッダー・ペイロード・署名の3部構成からなる文字列で、ペイロードの内容は誰でもデコードして読めますが、署名によって改ざんを検知できる仕組みになっています。「読める」ことと「改ざんできる」ことは別問題であり、秘密鍵を持たない限り検証に通る形での書き換えはできません。手元のJWTの中身を確認したい場合はJWTデコーダーが便利ですが、このツールは内容のデコード表示のみを行うものであり、署名の検証までは行っていない点に注意してください。