📘
「よし、JWTを使おう!」となったら最初に考えること
私は認証トークンとしてJWTをよく使います。
初めてJWTを使った時は
「なんかよくわからないからコピペで使おう。なんかうまくいってるからヨシ!」
って感じでした。
でも何度も使ってると
「こうやればいいんだ」
ってだんだん理解ができてきます。
その際に「最初からちゃんと意識しておけばなー」って思ったことを過去の自分に伝えるつもりで記事にします。
その1:暗号化方式をどうするか
共通鍵にするか、対象鍵にするか、って話。今だとHS256(共通鍵)にするか、RS256(対象鍵)にするか、になる?
- 共通鍵
- JWTの作成、検証を同じ鍵で行う
- 作成者、検証者が同じならこっちでOK
- 対称鍵
- 作成を秘密鍵、検証を公開鍵で行う
- 作成者と検証者が違うならこっち
- 要は鍵をどうするか、って話
- コンサートのチケットで例えると対称鍵方式だと、入場のチケット確認をアルバイトにお願いすることができる(公開鍵をアルバイトに渡してチケットの確認をして貰うイメージ)
- 共通鍵だとチケットは自分で確認しないといけない(共通鍵を他人に渡したら、勝手にチケットを作成される可能性がある)
- ただし、公開鍵方式は「鍵を渡す」という行動が入る以上「公開鍵と間違えて秘密鍵渡しちゃった!」なんてミスが起こる可能性がある。
- 共通鍵方式なら「鍵を渡す」という行為自体NGのため、「渡す鍵を間違えた」という心配をしなくていい。
その2:予約済みクレームをどうするか
- JWTには予約済みクレームというものがある(予約語みたいなもの)
- 予約済みクレームは使わなくてもいい
- しかし「予約済みクレームを使うのか?使うとしたらどうするか?」を考えれば、トークンとして必要なものは大体揃う
- 予約済みクレームを使うなら検証もちゃんと実装すること
iss
- 「誰がこのJWTを発行したのか?」
- コンサートチケットで例えると、
iss
: "○木坂46" やiss
: "○もいろクローバーZ" など、このチケットはどのアイドルグループのものか、になる - これがないとそれぞれのグループのチケットを作るためにそれぞれの鍵を用意しないといけない
sub
- 「このJWTのアプリ内での使い道は何?」
- コンサートチケットで例えると、
sub
: "入場チケット" やsub
: "グループ関係者" などになる - 入場チケットを使ってグループ関係者としてアイドルの控え室に行けたらやばいっすね、って話
aud
- 「このJWTは誰向けのもの?」
-
iss
やsub
はJWT作成者が使うが、aud
は作成者以外が使う - コンサートチケットで例えたいが、うまい例えが思いつかない
exp
- 「いつまでこのJWTは使えるの?」
- 有効期限
nbf
- 「いつからこのJWTは使えるの?」
iat
- 「このJWTはいつ発行されたの?」
jti
- JWT固有のID
- コンサートチケットでいうと、チケットに振られた固有の番号。特定のチケットを無効にしたい時に使う
大体こんな感じ
その3:payloadに何を含めるか
- ユーザーのIDを含めるのか、役割を含めるのか、など。
- 要はトークン本体に何を含めるのか、という話
- JWTのpayloadに秘匿性なんてないのでパスワードなど絶対に含めてはいけない
- コンサートチケットに、電話番号やemail、パスワードなどそのまま書いてあったら怖いですよね、って話。
JWTサンプル
実際のJWTがこれ
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiYXVkaWVuY2UiLCJhdWRpZW5jZTIiXSwiZXhwIjoxNjg4NzMwMTg2LCJpYXQiOjE2ODg3MjgzODYsImlzcyI6Imlzc3VlciIsImp0aSI6IjM5ODE0YzNkLTczMDUtNDgyNS1iOGMwLTUwYzA4MGE1ODBmOSIsIm5hbWUiOiJ5dXlhbiIsIm5iZiI6MTY4ODgxNDc4Niwicm9sZSI6ImFkbWluIiwic3ViIjoic2FtcGxlLWp3dC1zdWJqZWN0In0.fXiaAQctQiS91s9bi7B_lkoYU-I3HvlT5GLd6y3QJDg
header部分
# headerの中身
{
"alg": "HS256",
"typ": "JWT"
}
payload部分
# payloadの中身
{
"aud": [
"audience",
"audience2"
],
"exp": 1688730186,
"iat": 1688728386,
"iss": "issuer",
"jti": "39814c3d-7305-4825-b8c0-50c080a580f9",
"nbf": 1688814786,
"sub": "sample-jwt-subject",
"name": "yuyan",
"role": "admin"
}
こんな感じ
JWTを使う上での注意点
- JWTは検証しなくても中身はわかるので
payload
にパスワードなど秘密情報を含めてはいけない。 - JWTを個別に無効にするには別の工夫が必要。「ログアウトしたときにそのJWTを無効にしたい」っていうのはJWTだけで行うのは難しい(jtiを記憶するための何かが必要)
Discussion