JWT
#認証 #セキュリティ
https://scrapbox.io/files/6363d11c1ea3b2001d804c54.png
トークンベースの認証とは? 仕様とJWTのメリット、デメリット| Okta
JWTについて調べてみた
JWTの前に認証トークンの歴史
JWTのような認証トークンが登場するまでは、パスワード認証が利用されていた。
ただ、パスワード認証は、セキュリティ強度が低いことが徐々に問題になり始めた。
そこでトークン認証という手法が生まれた。
JWT(JSON Web Token)とは
JWTは認証トークンの一種。
オープンスタンダード、標準規格となっており、多くのWebサービスで使われてる仕組み。
JWTの中身は以下のようになってる
1. ヘッダー:このスペースには、トークンのタイプと関与する署名アルゴリズムを定義します。
2. ペイロード:このセクションには、トークン発行者、トークンの有効期限などを定義します。
3. 署名:安全な署名によって転送中にメッセージが変更されなかったことを確認します。
JWTの中身
以下がJWTそのもの
重要.icon {Base64エンコードされたヘッダ}.{Base64エンコードされた JSON の中身}.{電子署名}
= {ヘッダ}.{ペイロード}.{署名}
JWTでは、ヘッダとペイロードのJSON形式をBase64でエンコードして保持してる。
電子署名はハッシュ値をそのまま利用。
トークン認証の仕組み
トークン認証では、リソースサーバー(アクセスしたいサーバー)が認証を行うのではなく、認証サーバーという別のサーバーが行うことになる。
この認証サーバーが、ユーザー要求の検証を行い、成功したらトークンを発行するようになる。
ユーザーはこのトークンを鍵にして、リソースサーバーにアクセスするようになる。
https://scrapbox.io/files/6363d0716b9dcb00237d927f.png
それを踏まえてJWT認証のフロー・仕組み
登場キーワード
認証サーバー, リソースサーバー, JWT, 秘密鍵/公開鍵, ユーザー
フロー
1. ユーザーは、認証サーバーに対して何かしらの手段でログイン(password, oauth, ...)を行う
2. 認証サーバーは、ログインを検証して成功したら、事前に所持してた秘密鍵でJWTを発行してユーザーに渡す
3. ユーザーは、リソースサーバーにアクセスする際にJWTを一緒に渡す
4. リソースサーバーは、JWTを公開鍵で検証して成功したら、JWTのクレーム情報を参照する(有効期限もチェックする)
5. リソースサーバーは、クレーム情報からユーザーを識別して、必要な処理を行って、ユーザーにレスポンスを返す
point.icon リソースサーバーがやることは、JWTの検証とユーザー識別情報の確認だけ
point.icon リソースサーバーがJWTを自前の情報と突き合わせなくていいことから「ステートレスな認証」と呼ばれる
※ Session認証は逆に「ステートフルな認証」と呼ばれる
参考:JWT認証の仕組み・脆弱性について軽くまとめ | deecode blog
セキュリティの注意点
JWTは基本的に、発行したら有効期限が来るまで無効化できない
参考
JWTの無効化実装例
サーバサイドでJWTの即時無効化機能を持っていないサービスは脆弱なのか? - くろの雑記帳
不正者にJWTを盗まれたら、普通に不正アクセスされちゃう
JWTが門を通る鍵になっており、その鍵を盗まれたら、そりゃあ不正アクセスされちゃうよ
現実の世界と同じ
多段階認証とかの仕組みを入れてると、セキュリティ強度は増すけど。それはセキュリティ要件次第だよね。
JWTの保存場所はCookieかLocalStorageどっちがいいの?
セキュリティ要件によって変わる
XSSの前では、攻撃コストを考慮しなければ、どっちの方法でも無力。
ただ、HttpOnly有りのCookieに保存する方が、LocalStorageに保存するよりも攻撃コストは高くなる。
ので、少し安全になるっちゃなる。
参考:
XSSリスクを考慮した上で、トークンをin-memory、localStorage、Cookieのどれに保存する? - bontamoffu’s blog
【PoC編】XSSへの耐性においてブラウザのメモリ空間方式はLocal Storage方式より安全か? - Flatt Security Blog
SPAセキュリティ入門~PHP Conference Japan 2021
アクセストークン、リフレッシュトークンの仕組み
参考:Refresh Token: どのような場合に使用し、どのように JWT と相互作用するか
ここで言うアクセストークンとは、つまりJWTのこと。
リフレッシュトークンは、クライアントが認証サーバーに対して持つトークンのこと。
アクセストークン(JWT)の有効期限が切れたら、クライアントがリフレッシュトークンを持って再度、認証サーバーからアクセストークンをもらいに行ける。
こうすることで、アクセストークンの有効期限が切れる度に認証を行う必要がなくなる。
ただし、リフレッシュトークンの有効期限が切れたら、再度認証を行う必要はある。
アクセストークンは短く、リフレッシュトークンは長く
有効期限の話。
アクセストークンは盗まれやすいので、有効期限を短くしておく最低でも1時間以内にしておくといい。
対して、リフレッシュトークンは有効期限を長めに持っておくといい。
こいつは盗まれにくいはず。というか盗まれにくくすべき。
「リフレッシュトークンは、Cookieに保持する」的な対策したりしなかったり。
少なくともLocalStorageに置くのは危険かもしれない。
もし、アクセストークンが盗まれたとしても有効期限が短いので、そこまで長く悪さはできない。
事例として、Chatworkなどでは、JWTが盗まれる前提でアクセストークンの有効期限を30分とかにしてるらしい。
その他参考
セキュリティ視点からの JWT 入門 - blog of morioka12
RFC 8725 - JSON Web Token Best Current Practices 日本語訳
RFC 8725 JSON Web Token Best Current Practices をざっくり解説する - Qiita
Q&A
q.icon JWTって有効期限が切れた場合どういう流れを辿るの?
a.icon JWTの有効期限が切れた場合、そのJWTは無効になり、リソースサーバーでの検証も失敗する
その場合、クライアントサイドは、認証サーバーに再度JWTを発行してもらうことになる
hr.icon
JWTのログアウト問題について
調査内容
JWT絵認証を行っているAPIにおいて、ログアウトはどのように実装すべきでしょうか?ログアウト時にトークンを失効リストに追加し、認証時に失効リストをチェックするしかないのでしょうか?
はい。細かいことを言えばいくつかの実装が考えられますが、どれも似たような感じになるでしょうね。
ただ、そうなるとJWTをセッション管理に使うメリットがない気がします。なので、即時ログアウトはあきらめて、その代わりセッションタイムアウトを短めに設定し、リフレッシュトークンが使われた時点でログアウトしているユーザには再発行しないようにする(ログアウトからのタイムラグは許容する)か、JWT以外の方法を使うのがよいと思います。
hr.icon
JWTをめっちゃ理解しにいく
Refresh Token: どのような場合に使用し、どのように JWT と相互作用するか
JWT・Cookieそれぞれの認証方式のメリデメ比較 - Qiita
「JWTはステートレス」って言ってる意味がやっとわかったonigiri.w2.icon
JWTが送られてきたサーバー側ってどういう風に認証するんや?ってなってたんやけど...。
どうやら、デジタル署名の検証をするだけっぽい。
「検証が成功するトークンを持ってるってことは、こいつは認証済みのユーザーや」ってのが把握できるようになる
JWTのペイロード(クレーム)には、ユーザーを識別できる情報を入れておけば、そのユーザーの情報をサーバー側で参照すればいいって話になる。