あやきラボ

ソフトウェアエンジニアの生存戦略

JWTの仕組みと注意点

この記事では、JWTの仕組みと注意点を紹介します。

対象読者は、JWTをなんとなく使っているが、仕組みについて自信を持って説明できない人です。

この記事を読めば、JWTを扱うコードを読んだときに何をしているのか理解でき、セキュリティ上の落とし穴を避けられるようになります。

ぜひ最後までご覧ください。

JWTとは何か

JWTとは、認証した事実を証明するトークン形式の1つです。正式名称はJSON Web Tokenで、「ジョット」と読みます。

Cookieを使ったセッション管理の仕組みの記事で紹介した「クライアントサイド方式」の代表例がJWTです。ユーザー情報に署名を付けてトークンとして発行し、ブラウザに保存させます。

JWTの最大のメリットは、認証サービスにアクセスせずにユーザー情報を取得できることです。サーバーサイド方式では、リクエストのたびにデータベースやRedisにセッション情報を問い合わせる必要があります。JWTなら、トークン自体にユーザー情報が含まれているため、この問い合わせが不要になります。

JWTを使ったトークンの受け渡し
JWTを使ったトークンの受け渡し

JWTの構造

JWTは、ドット(.)で区切られた3つのパートで構成されています。

xxxxx.yyyyy.zzzzz

それぞれHeader、Payload、Signatureと呼ばれます。

署名アルゴリズムトークンの種類を指定します。

{
  "alg": "HS256",
  "typ": "JWT"
}

Payload

ユーザーIDや有効期限など、実際に伝えたい情報(クレーム)を格納します。

{
  "iss": "https://example.com",
  "sub": "1234567890",
  "aud": "https://api.example.com",
  "exp": 1735689600,
  "iat": 1735686000,
  "jti": "abc123"
}

RFC 7519では、以下の登録済みクレームが定義されています。いずれも必須ではありませんが、よく使われるものです。

  • iss(Issuer): トークンの発行者
  • sub(Subject): トークンの主体(通常はユーザーID)
  • aud(Audience): トークンの受信者(このトークンを受け入れるべきサービス)
  • exp(Expiration Time): 有効期限
  • iat(Issued At): 発行日時
  • jti(JWT ID): トークンの一意な識別子(リプレイ攻撃対策に使用)

これらに加えて、アプリケーション独自のクレーム(例: nameroleなど)を追加することもできます。

Signature

HeaderとPayloadを秘密鍵で署名したものです。これにより、トークンが改ざんされていないことを検証できます。

HeaderとPayloadはBase64エンコードされているだけなので、トークンを受け取ったクライアント側でデコードして中身を見ることができます。署名は改ざん検知のためのものであり、暗号化ではありません。この点は非常に重要です。

JWTの注意点

JWTを安全に使うためには、いくつかの注意点があります。

署名を必ず検証する

Base64デコードすればPayloadの中身が見られるため、署名を検証しなくてもクライアント側でユーザー情報を取得できてしまいます

しかし、署名を検証しないと、攻撃者が偽造したトークンを受け入れてしまう危険があります。トークンを受け取ったら、必ず以下を検証してください。

  • 署名が正しいか
  • 有効期限(exp)が切れていないか
  • 発行者(iss)が期待する値か
  • 受信者(aud)が自分のサービスを指しているか

署名アルゴリズムを適切に管理する

署名アルゴリズムに関連した攻撃手法がいくつか知られています。対策として、以下を心がけてください。

Payloadに機密情報を入れない

前述の通り、Payloadはクライアント側でデコードして中身を見ることができます。パスワードやクレジットカード番号などの機密情報は絶対に入れないでください。

ログアウト処理の難しさ

JWTの大きな課題は、一度発行したトークンをサーバー側から即座に無効化できないことです。

サーバーサイド方式なら、データベースからセッション情報を削除すれば即座にログアウトできます。しかしJWTは、トークン自体が有効期限を持っているため、期限が切れるまで有効なままです。

この問題への対策は主に2つあります。

トークンの有効期限を短くする

有効期限を数分〜数十分と短く設定します。期限が切れたら、ユーザーに再度ログインしてもらうか、別途発行した長寿命のリフレッシュトークンを使って新しいJWTを取得させます。万が一トークンが漏洩しても、有効期限が短ければ被害を最小限に抑えられます。

無効化リストを管理する

ログアウトしたJWTのID(jtiクレーム)をデータベースに保存しておき、トークン検証時にチェックします。ただし、この方法はサーバーサイドでの問い合わせが必要になるため、JWTの「問い合わせ不要」というメリットが薄れます。

さいごに

JWTの仕組みと注意点について、理解していただけましたでしょうか?

JWTは便利ですが、仕組みを理解せずに使うとセキュリティリスクにつながります。まずは自分のプロジェクトで、JWTがどのように発行・検証されているか確認してみてください。

最後までご覧いただきありがとうございました。また別の記事でお会いしましょう。