【入門編】 JWTの有効期限(exp)検証漏れによるトークン再利用攻撃 – オフェンシブセキュリティ & リバースエンジニアリング防御ガイド

「期限切れの合鍵」がなぜ危険?JWTの有効期限(exp)をめぐるセキュリティの落とし穴

こんにちは!今日は、Webサービスの「身分証」として広く使われている「JWT(JSON Web Token)」についてお話しします。

エンジニアの皆さんがログイン機能を作る際、ユーザーが一度ログインしたら、ページを移動するたびにパスワードを入力しなくてもいいようにするためにJWTを使うことがよくありますよね。でも、この便利な仕組み、実は「使い方を間違えると、とんでもないセキュリティホールになる」ことをご存知でしょうか?

今回は、JWTの「有効期限(exp)」という非常にシンプルな仕組みに焦点を当てて、なぜそれが大切なのか、泥棒の視点から解説していきます。

—

家の鍵に例えてみよう

皆さんが住んでいるマンションの鍵を想像してみてください。その鍵には、「この鍵は来週の火曜日に期限が切れます」というシールが貼ってあるとします。

もし、あなたが引っ越した後にその古い鍵を道端に落としてしまったらどうなるでしょう?

  • 有効期限の仕組みがある場合: 泥棒がその鍵を拾っても、火曜日を過ぎていれば、もうあなたの部屋のドアは開きません。
  • 有効期限がない(チェックしていない)場合: 泥棒は、何ヶ月経ってもその鍵を使って、いつでもあなたの部屋に侵入できてしまいます。

Webの世界におけるJWTも全く同じです。JWTには「exp(Expiration)」という「いつまで使えるか」を示す項目があります。 もしサーバー側でこの「期限」をしっかりチェックしなかったら、一度盗まれたトークンは「永遠に使えるマスターキー」になってしまうのです。

—

攻撃者はここを狙っている:リプレイ攻撃の恐怖

JWTを盗む方法は、実はたくさんあります。Wi-Fiの盗聴、PCのウイルス感染、あるいはブラウザに保存されたトークンを他の誰かが覗き見るケースなどです。

もし攻撃者が有効なJWTを手に入れたとき、サーバー側で「このトークンの期限は過ぎていないか?」というチェック(検証)を怠っていると、攻撃者はそのトークンを何度でも使い回します。これを「リプレイ攻撃(再利用攻撃)」と呼びます。

サーバーは「お、このトークンは正しい署名がされているな。じゃあログイン中なんだね、どうぞ!」と、攻撃者を正規のユーザーとして信じ込んでしまうのです。これが最も恐ろしい「認証のすり抜け」です。

—

どうやって防げばいいの?

対策はシンプルです。「サーバー側で期限を厳格にチェックすること」。これに尽きます。

多くのJWTライブラリには、期限チェックの機能が組み込まれています。例えば、Node.jsの jsonwebtoken というライブラリを使う場合、検証時に以下のようなコードを書くのが基本です。

const jwt = require('jsonwebtoken');

// サーバーに送られてきたトークンを検証する関数
function verifyToken(token) {
    try {
        // verifyメソッドは、トークンの署名検証に加えて、
        // 内部で自動的に「exp(有効期限)」が過ぎていないかもチェックしてくれます
        const decoded = jwt.verify(token, 'あなたの秘密の鍵');
        console.log('認証成功!ユーザー情報:', decoded);
    } catch (err) {
        // ここで「TokenExpiredError」などが飛んできたら、期限切れです
        console.error('認証失敗:トークンが無効、または期限切れです');
    }
}

さらに安全にするために:ブラックリスト運用

「でも、ログアウトしたユーザーのトークンを今すぐ無効にしたいときはどうすればいいの?」という疑問が浮かぶはずです。

その場合は、「ブラックリスト」という仕組みを使います。

1. ユーザーがログアウトしたら、そのトークンの「ID(jtiという項目)」をRedisなどの高速なデータベースに保存します。
2. ログイン状態をチェックするたびに、「このトークンのIDはブラックリストに入っていないかな?」と確認します。
3. 入っていれば、たとえ期限内でもアクセスを拒否します。

—

まとめ:一歩ずつ安全な仕組みを作ろう!

セキュリティと聞くと難しく感じるかもしれませんが、要は「身分証をチェックする係員が、期限切れを見逃さないようにする」というシンプルなルールの徹底です。

1. expを必ず含める: 発行時に有効期限をセットするのを忘れないでください。
2. 検証をサボらない: サーバー側でライブラリの検証機能を必ず呼び出してください。
3. ログアウト処理を作る: ブラックリスト運用を検討し、ユーザーが「もう使わない」と言った鍵はすぐに無効化しましょう。

最初は面倒に感じるかもしれませんが、一度仕組みを作ってしまえば、それがユーザーの皆さんを守る強固な盾になります。「ログイン機能を作った!」という時は、ぜひもう一度、この「期限チェック」のコードを見直してみてくださいね。

皆さんのサービスが、より安全で愛されるものになることを応援しています!

コメント

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