ぼくのかんがえたさいきょうのAPI管理(JWT)


環境

サーバからAPIを叩いてjsonを取ってくるWEBシステム
フロントはJavaScript,jQuery,Riotで組まれている。
認証サーバとAPIサーバが同一(マシンもIPもシステムも)

問題点

JWTにjsonはbase64でエンコードされたものであり、暗号化はされていない。
実装によるがLocalStorageに値を入れる事が多いが、LocalStorageはJSから自由に読み込む事が可能なためXSSにより任意のJSが実行された場合は容易にAccess Tokenを盗む事ができる。
※改ざんされないだけであり、盗まれるたものを利用される恐れはある。
(セッションハイジャック)

解決案

XSS,CSRF対策がしてあるのは大前提

  • Access TokenをCookieに格納して"HTTP Only"と"Secure"フラグを付ける。
  • Access Tokenやセッショントークンは一定時間ごとに更新される。(30分等)

機構

1. ログイン時にサーバからクライアントに以下の3つを渡す。

クライアント側

value name store place expire element Desc
Access Token Session Storage 30m user_num,token用乱数 必ずJWT
Local Key Local Storage 30d user_num,expire,key用乱数 コストが気になれば通常のjsonでも可
Cookie Key Cookie LocalStorage Keyと同じ期間 user_num,key用乱数 HTTPOnly,Secure(コストが気になれば通常のjsonでも可)

※ user_num : user_idと1対1になる乱数(JWTの内容は暗号化されないのでuser_idそのままはまずい)

DB

value name Desc
User ID ログイン時に使うid
User Num user_idの代わりにjsonへ含める乱数値
Refresh Hash Sessionが切れた場合に新規Access Tokenを発行する場合の検証につかうHash値
Salt 上記ハッシュを生成する際に使ったソルト値

サーバ側(内部変数)

value name
Access Token
User Num
Local Key
Cookie Key

Refresh Hashの生成方法

  1. Local Key+Cookie keyをハッシュ化する。
  2. 1のハッシュ+ソルトをハッシュ化する。

2.通常(画面遷移なし)利用時

フロントエンド側は定期的にサーバと通信を行っているものとする。

  1. クライアントはAccess Tokenをサーバへ送信する。(Cookie keyも勝手に送られるけどきにしない。)
  2. サーバは送られてきたAccess Tokenと内部変数のAccess Tokenが一致するかを検証する。異なればログインページへリダイレクトする。
  3. 一定時間(30分)毎にAccess Token,Local Key,Cookie Keyの3つともクライアントへ送信する。クライアントはそれぞれを格納する。(※この段階ではLocal KeyCookie Keyは内部変数で保持しているのみで、Refresh Hashは生成・保存されていない。)
  4. クライアントとのセッションが切れた段階でサーバはLocal KeyCookie Keyを使いサーバはRefresh Hashを生成し、DBへ保存する。

3.ブラウザやタブを閉じた後、再開時

Access TokenSession Storageに入っているため、ブラウザを閉じたりタブを閉じれば消えてしまうため再度Access Tokenを取得する必要がある。

  1. クライアントはサーバに対してLocal KeyCookie keyを送信する。
  2. サーバはKeyの検証を行う。
    1. クライアントから送らてきたLocal Key,Cookie keyが改竄されていないかJWTのチェックをする。※KeyがJWTの時のみ
    2. Local Key,Cookie keyとDBにあるソルトを使いRefresh Hashを生成する。(1のRefresh Hashの生成方法を参照)
    3. 1のRefresh HashとDBのRefresh Hashを突き合わせる。
    4. 一致すれば新規のAccess Tokenを発行する。異なれば ログイン画面へリダイレクトする。
  3. サーバはクライアントにAccess Token,Local Key,Cookie Keyを送信する。
  4. クライアントは新規の3つをそれぞれ格納する。

4.その他

  • JWTのjsonが改ざんされていた場合
  • Access TokenがなくLocal Key,Cookie keyもない場合
  • Local Key,Cookie keyの期限が切れている

これらはすべてログイン画面へリダイレクトさせる。