こんにちは。セキュリティの世界へようこそ。
日々、システムを守る最前線にいると、「完璧な鍵なんて存在しない」という事実に直面します。でも、だからこそ面白い。今日は、開発現場で誰もが一度は悩み、そして一度は挫折しがちな「JWTのログアウト」という難題について、一緒に紐解いていきましょう。
JWTは「魔法の通行手形」だけど……
まず、JWT(JSON Web Token)をイメージしてみてください。これは、あなたの家の鍵というよりは、「顔パスで入れるVIPチケット」に近いです。
一度そのチケットを手に入れれば、有効期限が切れるまで、誰が持っていようと門番は中に入れてしまいます。これがJWTの「ステートレス」という特徴です。サーバー側で誰が入ったかを記録しなくてもいいので、非常に高速で効率的。でも、もしそのチケットを泥棒に盗まれてしまったら?
有効期限が切れるまで、泥棒は堂々とあなたの家に居座り続けます。「ログアウトボタンを押したのに!」とあなたが叫んでも、チケット自体が有効なら、門番は「どうぞお入りください」と言ってしまうのです。
「ブラックリスト」という名の指名手配書
では、どうすればいいのでしょうか。答えはシンプル。「門番に、盗まれたチケットの指名手配リスト(ブラックリスト)を渡しておく」のです。
これが、今回解説する「Redisを使ったブラックリスト管理」の正体です。
Redisが最強の相棒である理由
なぜRedisを使うのか。それは、この指名手配リストは「爆速」で照会できなければ意味がないからです。ユーザーがリクエストを送るたびに、重いデータベースを検索していたら、システム全体が悲鳴を上げてしまいます。Redisはメモリ上で動くため、一瞬で「このチケットは無効だ!」と判断できるのです。
実装の設計パターン
では、実際にどう実装するか、泥臭い現場の知恵を少しだけ共有しますね。
1. ログアウト時の処理
ユーザーがログアウトボタンを押した瞬間、そのJWTの「JTI(JWT ID)」を取り出し、Redisに保存します。
// ログアウト処理のイメージ(Node.js / Express)
app.post(‘/logout’, async (req, res) => {
const token = req.headers.authorization.split(‘ ‘)[1];
const decoded = decodeToken(token); // トークンを解読
const jti = decoded.jti; // トークン固有のIDを取得
const exp = decoded.exp; // 有効期限を取得
// 有効期限が切れるまでの時間を計算
const ttl = exp – Math.floor(Date.now() / 1000);
if (ttl > 0) {
// Redisに指名手配リストとして保存(有効期限が来たら自動消滅するように設定)
await redisClient.set(blacklist:${jti}, ‘true’, ‘EX’, ttl);
}
res.send(‘ログアウトしました。もうそのチケットは使えません!’);
});
2. 認証ミドルウェアでのチェック
リクエストが来るたびに、そのチケットがブラックリストに載っていないかを確認します。
// 認証チェックのイメージ
async function verifyToken(req, res, next) {
const jti = getJtiFromToken(req);
// Redisにデータが存在すれば、それは「無効化されたチケット」
const isBlacklisted = await redisClient.get(blacklist:${jti});
if (isBlacklisted) {
return res.status(401).send(‘このチケットは無効です。再ログインしてください。’);
}
next(); // セーフ!
}
パフォーマンスへの影響と、賢い付き合い方
「毎回Redisに問い合わせたら遅くなるのでは?」と心配になりますよね。その直感は非常に鋭い。ですが、Redisの応答速度は1ミリ秒以下です。現代のWebアプリケーションにおいて、このコストは無視できるレベル。
ただし、「ブラックリストが巨大化しすぎてメモリを圧迫しないか?」という点は注意が必要です。そのため、上記のコード例のように、JWTの有効期限(exp)に合わせてRedisのデータも自動消滅(TTL設定)させるのが鉄則です。
まとめ:セキュリティは「バランス感覚」
今回紹介したブラックリスト方式は、完璧な「ステートレス」からは少し離れます。でも、セキュリティにおいて「利便性」と「安全性」のバランスを取ることは、最高峰のエンジニアにとっても永遠の課題です。
- JWTは便利だけど、盗まれたら終わり。
- ログアウト時は、指名手配リスト(Redis)にIDを登録する。
- 期限が切れたら自動で消えるように設定する。
これだけで、あなたのシステムの堅牢性は劇的に向上します。一歩ずつ、着実に。今日からこの「指名手配リスト」の考え方を、ぜひあなたの開発の引き出しに加えてみてください。
また何か壁にぶつかったら、いつでも相談してくださいね。応援しています!
コメント