👌

JWTについて調べてみた

2022/05/24に公開

JWTってなんぞ?

JWTとは
  • JSON Web Token の略
  • 電子署名付きのURL-safe(URLとして利用出来る文字だけ構成される)なJSON
  • 電子署名により、JSON の改ざんをチェックできる

つまり、改ざんできないJSON

電子署名とは
  • 電子認証局から発行される「電子証明書」を用いて、なりすましの防止や情報の改ざんを防止する技術
  • その文書が改ざんされていないことを確認するために使う

【署名者側】

  1. データをハッシュ化する
  2. 署名者は秘密鍵を使ってハッシュ値を暗号化する(電子署名)
  3. 2を1のデータ(ハッシュ化してないもの)に添付して送る

    【検証者側】
  4. データをデコードする
  5. 2の電子署名を公開鍵でデコード(署名者のハッシュ値が見れる)
  6. 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

使い所
  1. クライアントが、認証情報 (ログインID + パスワード) を送信
  2. サーバは、認証情報を確認してuser_idexp (有効期限)を含むJSONを秘密鍵で暗号化して JWTとして返却
  3. 以降クライアントは、認証済みリクエストとして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