👌
JWTについて調べてみた
JWTってなんぞ?
JWTとは
- JSON Web Token の略
- 電子署名付きのURL-safe(URLとして利用出来る文字だけ構成される)なJSON
- 電子署名により、JSON の改ざんをチェックできる
つまり、改ざんできないJSON
電子署名とは
- 電子認証局から発行される「電子証明書」を用いて、なりすましの防止や情報の改ざんを防止する技術
- その文書が改ざんされていないことを確認するために使う
【署名者側】
- データをハッシュ化する
- 署名者は秘密鍵を使ってハッシュ値を暗号化する(電子署名)
- 2を1のデータ(ハッシュ化してないもの)に添付して送る
↓
【検証者側】 - データをデコードする
- 2の電子署名を公開鍵でデコード(署名者のハッシュ値が見れる)
- 4と5を比較。ハッシュ値が同じならば改竄されていない。
セッション認証 vs トークン認証
違いは何か?
webブラウザとサーバーでやりとりする'もの'が違う。
方式 | やり取りするもの |
---|---|
セッション認証 | SessionID |
トークン認証 | トークン(ユーザー情報を暗号化したもの) |
セッション認証
- SessionIDに紐づくユーザー情報をサーバー側で持つ(Session)
- ログインが成功したユーザーが、SessionIDとそれに紐づくデータを作成し DBに保存(ユーザーID,名前etcの情報)
- ブラウザ側にはSessionIDのみを返却
- SessionIDはCookieに保存
- リクエスト時にHTTP HeaderのCookieをサーバーに送る
メリット、デメリット
良し悪し | 内容 |
---|---|
メリット | サーバー側にいろいろな情報の保存しておける |
デメリット | 毎回DBにアクセスする必要があるため負荷がかかる |
デメリット | 他のサービスなどに同じユーザー情報を使いたい時、ユーザー情報を持つDBにアクセスする設計にしないといけない |
つまり
SessionID = Sessionにアクセスする鍵
中には特に何の情報も入ってない
トークン認証
- ユーザー情報(user_id,有効期限)を含めて暗号化したトークンをサーバー側で発行
- 暗号化したトークンをCookieに保存(Local Storageに保存するメリットは個人的には不明...)
- 各リクエスト時、トークンを送信する
- サーバー側でトークンをデコードして、ユーザー情報などを確認
メリット、デメリット
良し悪し | 内容 |
---|---|
メリット | 不明 |
デメリット | トークンの暗号形式がバレると、ユーザー情報が簡単にわかる |
つまり
トークン = 暗号化されたユーザー情報
暗号形式バレると詰む
セキュリティ
脆弱性
- CokkieはここのところHttp-Onlyと呼ばれる、脆弱性対策が搭載されているらしい
- XSSの前にはCookieだろうがLocal Storageだろうが無力と思われる
- 情報を抜き取られるリスクを考慮して、パスワードetcの超極秘情報はブラウザに保存しないのが吉
- Cokkie, トークン内部に有効期限をつけると頻繁に内容を更新できていい感じな気がする
Use Case
使い所
- クライアントが、認証情報 (ログインID + パスワード) を送信
- サーバは、認証情報を確認して
user_id
とexp (有効期限)
を含むJSONを秘密鍵
で暗号化してJWT
として返却 - 以降クライアントは、認証済みリクエストとしてJWTを利用して通信
★JWT はサーバで秘密鍵を利用して改ざん検証をおこなうので改竄を検知できる
JWTの中身
中身概要
{ヘッダ}.{ペイロード}.{署名}
{Base64エンコードされたヘッダ}.{Base64エンコードされた JSON の中身}.{電子署名}
1. ヘッダ
項目 | 内容 |
---|---|
alg | 署名アルゴリズム。HS256 など |
typ | Tokenのタイプ。JWT 指定が推奨 |
☆alg
のみ必須項目
以下のフォーマットのJSONデータをbase64
エンコードすることでヘッダが作成される
# 例
{
"alg": "HS256",
"typ": "JWT"
}
# タイプはJWT
# HMAC SHA-256アルゴリズムを使っている
2. ペイロード
- JSONの本体
- ヘッダ同様
Base64
エンコードで作成
ベーシックな項目 | 内容 |
---|---|
exp | 有効期限 |
nbf | 期限開始日時: not before |
iat | JWT発行日時: issued at |
iss | 発行者(サーバ側)の識別子: issuer |
aud | 利用する側(クライアント側)の識別子: audience。通常URI 形式 |
jti | JWTの一意のID |
- これらの項目は
登録済みクレーム
と呼ばれる - ペイロードセクションにはJSONフォーマットに規定はなく、必須のキー情報などはない
- けれど、
登録済みクレーム
で定められた項目以外で利用するのは避けたほうが無難
以下のフォーマットのJSONデータをbase64
エンコードすることでヘッダが作成される
# 例
{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022
}
3. 署名
- JWTの正当性を保証するための電子署名
- 至って普通に電子署名
注意事項
ヘッダ情報の脆弱性
alg
の脆弱性が存在するため、中身をチェック
重要な情報を設定しないこと
- JWTの中身は
Base64エンコード
されただけ = 中身が簡単に確認できる - クライアント側に見えてはいけない内容は入れないべき
一度発行したJWTの無効化は難しい
- 一度認可したJWTを無効化扱いすることはできない
- 有効期限を短くしたり、即時無効化する必要がある場合は別途仕組みを用意する必要あり
Discussion