コース目次 / 第1章
分解する — 3つの部品と、読める中身
JWTがヘッダ・ペイロード・署名の3部品からなり、最初の2つはbase64urlエンコードなだけで誰でも読めることを、手元で確かめます。JWTは暗号化ではないと体で理解します。
JWT は、一見すると意味のない長い文字列です。でも、よく見るとピリオド . で3つに区切られています。
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiaGFydXRvIiwicm9sZSI6InVzZXIifQ.3Y_k...(署名)
法と倫理ゲート
手を動かす前に
このコースは攻撃の技術に触れます。実習してよい相手は、次の3つだけです。
- (a) 自分で作った練習用のやられ環境(このサイトが配る自作ターゲット)
- (b) あなた自身の許可された環境(自分の Thousand SKY・secret-notes-ctf など)
- (c) CTF 競技の中(規約の範囲で)
実在する第三者のシステムを許可なく触ることは、不正アクセス禁止法に触れます。 このゲートは、その線引きを毎回の入口で確かめるためのものです。詳しくは「セキュリティの法と倫理」へ。
3つの部品
. で割った3つは、それぞれ役割があります。
1つめ = ヘッダ(header) — このトークンの「作り方」。署名アルゴリズム(alg)などが入る。
2つめ = ペイロード(payload) — 中身。「誰か(user)」「権限(role)」「有効期限(exp)」など。
3つめ = 署名(signature) — 1つめと2つめが改ざんされていないことを保証する印。
前の2つは base64url というエンコード方式で、3つめだけが暗号的な署名です。
デコードしてみる — 鍵は要らない
いちばん大事な事実を、手を動かして確かめます。ヘッダとペイロードは、鍵がなくても読めます。 base64url は暗号ではなく、ただの文字の置き換えだからです。
ブラウザの開発者ツールのコンソールで、JWT のペイロード部分(2つめ)を atob でデコードできます。
// ブラウザのコンソールで。JWT の「2つめ」の部品を貼る。
// base64url は - _ を使うので、base64 の + / に戻してから atob する。
const part = "eyJ1c2VyIjoiaGFydXRvIiwicm9sZSI6InVzZXIifQ";
atob(part.replace(/-/g, '+').replace(/_/g, '/'));
// => '{"user":"haruto","role":"user"}'
node なら、もっと素直です。
// node で。base64url を直接デコードできる。
const part = "eyJ1c2VyIjoiaGFydXRvIiwicm9sZSI6InVzZXIifQ";
console.log(Buffer.from(part, 'base64url').toString());
// => {"user":"haruto","role":"user"}
{“user”:“haruto”,“role”:“user”} が、そのまま読めました。鍵も、パスワードも要りません。JWT のヘッダとペイロードは、誰でも——サーバも、ブラウザも、通信を覗いた第三者も——中身を読めます。これが試食で見た「見えるものは秘密ではない」の正体です。
JWT は「暗号化」ではない
ここを取り違えないことが、この章の芯です。
JWT は、暗号化されていません。署名(3つめ)は「改ざんされていないこと」を保証しますが、「中身を隠す」ものではない。だから——JWT のペイロードに、秘密を入れてはいけません。パスワード、クレジットカード番号、隠しておきたい個人情報。これらを JWT に入れると、トークンを持っている人(や覗いた人)全員に読まれます。
「署名 = 暗号化」という誤解が、実際の事故を生んでいます。JWT が守るのは完全性(改ざん検知)であって、秘匿性(中身を隠す)ではない。
持ち帰る一言
JWT の中身は、誰でも読める。 ヘッダとペイロードは base64url エンコードなだけで、鍵なしでデコードできます。JWT は暗号化ではなく、署名で改ざんを止めているだけ。だから秘密は入れない。では、その「改ざんを止める署名」は、どう働くのか。次の章で見ます。
こうなっていればOK
卒業まであと3章です。
この章はまだ完了していません。
保存できませんでした(プライベートブラウズ中かもしれません)。この端末に進捗は残りませんが、先へは進めます。