JWT@認証¶
はじめに¶
本サイトにつきまして、以下をご認識のほど宜しくお願いいたします。
01. JWT:JSON Web Token¶
JWTとは¶
『ヘッダー』『ペイロード』『署名』のそれぞれのJSON型データをbase64
方式によってエンコードし、ドットでつないだトークン。
Bear認証やOAuthのトークンとして使用できる。
ランダムな文字列をこれら認証のトークンとするより、JWTを使用した方がより安全である。
JWT仕様のトークンの種類¶
JWT仕様のトークンには以下の種類がある。
- JWT仕様のアクセストークン
- IDトークン (必ずJWT仕様)
- https://qiita.com/TakahikoKawasaki/items/1c1bcf24b46ebd2030f5#%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E3%83%88%E3%83%BC%E3%82%AF%E3%83%B3jwtid%E3%83%88%E3%83%BC%E3%82%AF%E3%83%B3%E3%81%AE%E5%8C%85%E5%90%AB%E9%96%A2%E4%BF%82
- https://zenn.dev/mikakane/articles/tutorial_for_openid#oidc-%E5%88%A9%E7%94%A8%E3%81%95%E3%82%8C%E3%82%8B-id-token-%E3%81%AE%E8%A6%8F%E7%B4%84
02. JWTによるトークンベース伝播による認証の仕組み¶
JWTの検証とは¶
JWT仕様のトークン (例:IDトークン) の有効期限や発行元認証局が正しいかどうかを検証する。
署名の仕組みを使用して、発行元認証局を検証する。
署名が共通鍵方式の場合¶
▼ 共通鍵方式の特徴¶
共通鍵方式では、秘密鍵を使用してJWT作成 (初回認証時) とJWT検証 (次回認証時) の両方を実施する。
例えば、SSOではない認証では、JWTの署名が公開鍵方式である。
ユーザー側とアプリケーション側に秘密鍵を置く。
▼ 初回認証時¶
初回認証時は、JWTを作成する。
- ユーザーは、ログインフォームにユーザーIDとパスワードを入力する。
- アプリケーションは、フォームの入力情報を含むリクエストを受信する。また、DBのユーザー情報と照合して認証処理を実行する。
- 認証が成功すれば、アプリケーションは秘密鍵を使用してJWTを作成する。
- アプリケーションは、JWTをレスポンスに含め、ユーザーに返信する。
- ブラウザは、JWTをLocalStorageやローカルマシンの
Cookie
ディレクトリに保管する。
▼ 次回認証時¶
認証の成功状態を維持するため、初回認証時にブラウザの保管したJWTを再利用する。
- ユーザーは、ブラウザの保管したJWTをリクエストに含め、アプリケーションに送信する。
- アプリケーションは、秘密鍵を使用して、JWTが有効か否かを検証する。
- JWTが有効であれば、認証成功とし、ユーザーにレスポンスを返信する。
署名が公開鍵方式の場合¶
▼ 公開鍵方式の特徴¶
共通鍵方式では、秘密鍵を使用してJWT作成 (初回認証時) 、公開鍵を使用してJWT検証 (次回認証時) を実施する。
例えば、SSOでは、JWTの署名が公開鍵方式である。
クライアント側に秘密鍵、IDプロバイダー側に公開鍵を置く。
▼ 初回認証時¶
初回認証時は、JWTを作成する。
- ユーザーは、IDプロバイダーのログインフォームにユーザーIDとパスワードを入力する。
- IDプロバイダーは、フォームの入力情報を含むリクエストを受信し、認証処理を実行する。また、DBのユーザー情報と照合して認証処理を実行する。
- 認証が成功すれば、IDプロバイダーは秘密鍵を使用してJWTを作成する。
- IDプロバイダーは、JWTをレスポンスに含め、ユーザーに返信する。
- ブラウザは、JWTをLocalStorageやローカルマシンの
Cookie
ディレクトリに保管する。
▼ 次回認証時¶
認証の成功状態を維持するため、初回認証時にブラウザの保管したJWTを再利用する。
- ユーザーは、ブラウザの保管したJWTをリクエストに含め、アプリケーションに送信する。
- アプリケーションは、IDプロバイダーに公開鍵をリクエストする。
- IDプロバイダーは、アプリケーションに公開鍵をレスポンスする。
- アプリケーションは、IDプロバイダーから取得した公開鍵を使用して、JWTが有効か否かを検証する。
- JWTが有効であれば、アプリケーションの認証処理は成功とし、ユーザーにレスポンスを返信する
03. JWTの運搬方法¶
HTTP認証の場合¶
▼ Bearer認証¶
トークンをAuthorization
ヘッダーに割り当て、リクエストを送信する。
POST https://example.com/foo
---
authorization: Bearer <ヘッダーJSONエンコード値>.<ペイロードJSONエンコード値>.<署名JSONエンコード値>
Authorization
ヘッダーはCookie
ヘッダーとは異なり、ローカルマシンに保管できない。
なお、APIではリクエストの送受信時にCookie
ヘッダーよりもAuthorization
ヘッダーの方が扱いやすいため、Authorization
ヘッダーでトークンを運ぶことになる。
また、スマホアプリもCookie
ヘッダーよりAuthorization
ヘッダーがいいらしい。
- https://qiita.com/hirohero/items/d74bc04e16e6d05d2a4a
- https://softwareengineering.stackexchange.com/a/141434
- https://www.bokukoko.info/entry/2015/12/20/%E8%AA%8D%E8%A8%BC%E3%82%92%E5%90%AB%E3%82%80_API_%E9%96%8B%E7%99%BA%E3%81%A7%E6%A4%9C%E8%A8%8E%E3%81%99%E3%81%B9%E3%81%8D%E3%81%93%E3%81%A8
- https://stackoverflow.com/questions/72180420/is-there-any-reason-to-use-http-header-authorization-to-send-jwt-token-instead-o/72182434#72182434
- https://qiita.com/ledmonster/items/0ee1e757af231aa927b1#%E8%AA%8D%E8%A8%BC%E3%81%AE%E5%9F%BA%E6%9C%AC%E6%96%B9%E9%87%9D
Form認証の場合¶
トークンをCookie
ヘッダーに割り当て、リクエストを送信する。
POST https://example.com/foo
---
cookie: Bearer <ヘッダーJSONエンコード値>.<ペイロードJSONエンコード値>.<署名JSONエンコード値>
04. JWTの作成¶
JWT作成の全体像¶
JWTは以下のサイトから取得できる。
例えばJavaScriptであれば、以下のような処理を実行し、JWTを作成する。
// <ヘッダーエンコード値>.<ペイロードエンコード値>.<署名エンコード値>
const token =
base64urlEncoding(header) +
"." +
base64urlEncoding(payload) +
"." +
base64urlEncoding(signature);
JWTの作成¶
▼ ヘッダーの場合¶
ヘッダーは以下のJSON型データで定義される。
署名のための暗号アルゴリズムは、『HS256
(共通鍵方式) 』『RS256
(公開鍵方式) 』『ES256
』『none
(署名なし) 』から選択できる。
const header = {
typ: "JWT", // JWTの使用
alg: "HS256", // 署名のための暗号アルゴリズム
};
▼ ペイロードの場合¶
ペイロードは以下のJSON型データで定義される。
ペイロードには、実際に送信したいJSONを設定する。
必ず設定しなければならない『予約済みクレーム』と、ユーザー側が自由に定義できる『プライベートクレーム』がある。
パラメーター名 | 対応するクレーム | 役割 | 例 |
---|---|---|---|
sub |
Subject | 一意な識別子を設定する。 | ユーザーID |
iss |
Issuer | JWTの発行元認証局を設定する。 | |
aud |
Audience | ||
exp |
Expiration Time | JWTの有効期限を設定する。 | |
jti |
JWT ID |
const payload = {
sub: "foo",
aud: "foo",
iss: "https://example.com",
exp: 1452565628,
iat: 1452565568,
};
▼ 署名の場合¶
例えばJavaScriptであれば、以下のような処理が実行されている。
const signature = HMACSHA256(
base64urlEncoding(header) + "." + base64urlEncoding(payload),
secret,
);
05. JWTの保持方法と安全度の比較¶
クライアント保持方法 | 組み合わせ | おすすめ度 | コメント |
---|---|---|---|
Cookie ヘッダー (ローカルマシンのディレクトリ) 、LocalStorage |
JWTのみ | △ 〜 × | いずれの方法でも、XSSによってJWTが盗まれる可能性がある。 |
Cookie ヘッダー |
プリフライトリクエスト | △ | Access-Control-Max-Ageの期間内だとCSRFでJWTが盗まれる可能性がある。 |
Cookie ヘッダー |
CSRFトークン | ⭕ | |
SameSiteCookie | ⭕ | SPAとAPIが同一オリジンの必要がある。 |
06. JWTの代替¶
- fernet token
- branca-token
- PASETO