JavaScript
JWT

ぼくのかんがえたさいきょうの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の期限が切れている

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