2018-09-22

JWTに関してのお伺い

http://b.hatena.ne.jp/entry/s/co3k.org/blog/why-do-you-use-jwt-for-session

適当コメントを書いたら

スーパーエンジニアに「そういうことではない」

と厳しい叱責を受けたため、無能の見識を書いてみた。

「聞くは一時の恥、聞かぬは一生の恥」のとおり、

せっかくの機会のため、びしばしセキュリティに関する認識の甘さを指摘してほしい所存

expの期限と任意セッションが切れないデメリットに対する私見

作ったシステムではexpは約1時間でやってしまいました(機密保持契約違反を恐れ多少ぼかしております)

私は無能なのでたぶんユーザーから報告を受けて

確認している間に1時間はかかるからいいやと思ってしまっていた

師はきっとJWT生成直後3秒でユーザー

「これは、セッションハイジャックか・・・!?

と気づいて通報

そして師が2秒で

「これは、セッションハイジャックだ!」

と検知してセッション遮断、秒速で一億円の被害が出るところを阻止する前提なのではないかと推測している

これは確かにJWTだと厳しそうだ

そもそもログインできるアプリなら

セッションハイジャック成功直後にパスワードを変更された場合

セッション任意に切れることに意味はないのでは、と思えてきたが、浅はかだろうか

(師はログインを即座に検知してセッションを切れるから問題ないのか)

とにかくアカウントロック機能を作れば上記懸念全てにきれい対応できそうに見えている

「定期的な鍵交換が必要」に関する私見

この理屈だと例えば.envに書くような他のkeyも定期的な交換が必要に見える

これはまずい、自分の今までの見識の甘さを思い知らされた

今使っているフレームワークリファレンスを見たが

keyは初回に設定したのみで、定期的な交換を勧める文が見つからない

私の検索力不足なのかと思ったが、もしかして彼らもこの危険性に気付いていないのではないか

JWTはhash化してつないでいる前提で

hashのkeyを総当たりで破る仮定で書く

私は無能なのでライブラリを用いることにしている

32文字keyが生成された

解読時間は下記を参考に、計算windows10電卓アプリを用いて手動で行った

https://ja.wikipedia.org/wiki/%E7%B7%8F%E5%BD%93%E3%81%9F%E3%82%8A%E6%94%BB%E6%92%83

数字大文字文字で約60の時は10桁で20万年と書いているが

現代の解析技術20万倍は速度が出ると仮定して1年として計算する

果たして、どのくらいの速度で鍵はやぶられると推定されるのか

とりあえず60を10乗した時点で(20文字相当)

6.0466176e+17

日本語に直すと60京4661兆7600億年かかる計算となった

実際にはこれが6.0466176e+17倍されさらに3600倍されつまりどういうことだ

これだけ長くともkeyの交換は必要なのであろうか

そもそも師は何年で交換したら安全と書いていないが、何年なら安全という意見だったのだろうか

「JWTはセッションIDを含めれば安全」に関する私見

から「そういうことではない」と指摘された点である

私の理解ではとかくuser_idのみ必要なら意味がないと思っていたため落ち込んでいる

まず、IDとpassを内蔵するネイティブアプリに対するapiサーバでの実装経験しかないこと

JWTが切れたら都度IDとpassを投げる方向でリフレッシュトークン実装しなかったことを告白しておく

そのためapiサーバ上記前提で用いた場合に考えたことを書く

webアプリのJWT実装経験はないので、そちらの論は差し控えさせていただく

JWT送信→user_id取得

では危険

JWT送信セッション(cookie形式?)送信切り替え→セッションからuser_id取得

だと安全になるのか検討する前提で記載する

とりあえず思いついたのは下記だった

通信途中で傍受されてログイン情報が奪われる危険が上がる
アプリから直接ログイン情報が奪われる危険が上がる

通信途中で傍受される危険に関して

tokenはheaderにbearerで付けユーザーID(あるいはそれに代わる特定可能識別子)が含まれ

おそらく一般構成仮定で書く

https通信するのでパケットキャプチャによる傍受は不可能と思っていた

(http通信するのはJWTとかcookieとか関係なく傍受できるため考慮しない)

0に何をかけても0なので、何回送っても解読されないならJWTを何回送っても問題ない

というかJWTが抜けるなら同様にheaderに付けるcookieでも抜けると思うので

JWTだからといって危険性に差はない、という論拠により安全性は変わらないという個人的結論になった

※余談だが、たまに送る回数が少ない方が安全という

言説を見るのだが、個人的には上記理由で納得できていない

アプリから情報が抜かれる危険性に関して

クライアントネイティブアプリ場合

攻撃者がアプリに保存されたJWTが取得できるならIDもpassも同じ方法で抜けそうに見えた

(厳密には保存場所が違ったかもしれんが実装依存なので同一とする)

その前提のため、わざわざ

JWT送信セッション(cookie形式?)送信セッションからuser_id取得 

接続しても、おそらくcookie形式で送れる何かもJWTらと同じ方法で抜かれると思われる

まりcookieだろうがJWTだろうがアプリから直接情報が抜かれる危険性には変わりがないという結論になった

結論

まりcookieだろうがjwtだろうがidpasswordの組だろうが同じ危険性で抜かれる可能性があり、いずれでも同じことができるなら

JWT→user_id

でいいじゃん、わざわざcookieと同様の形式を間に挟むの無駄じゃん、となりコメント発言に至った

ここまで書いて、常にJWTにsession_idを含めておいて送ることを意図されていた可能性にも気づいたが

それならもっと無駄なため考慮しない

セッションにするメリットとして唯一思いついているのは任意サーバ側でセッションを切れることだが

それを指していたのであろうか

それは最初段落問題と同一と思っている

余談だが、ブコメ雰囲気日和って「ユーザーIDのみ入れ」(そもそもJWTを自然に作れば入るのだが)

というセッションストア的にJWTに他の情報を入れると入れない時に比べて危険性があがることに同意したような記載をしてしまったが

結局JWTが奪えたら中身に関係なくbearerとしてセットして接続するだけなので

正直JWTを使った時点でついでにセッションストアのように使おうが使わまいがセキュリティ的にそこまで変わらないのでは、と思っている

強いて上げるならセッションに保存している内容が分かる可能性があり、サーバー内部の実装が推測できる危険があるくらいだろうか

でも暗号化したらよいのでは、と思った

私的結論

expの期限と任意セッションが切れないデメリットに関して

expを適切に設定しつつ、必要ならアカウントロック機能を入れる

(アカウントロック機能はJWTに関係なく被害の増加を抑えられる可能性がある)

定期的な鍵の交換について

長いkeyを設定すれば不要

「JWTはセッションIDを含めれば安全」について

少なくともapiサーバネイティブアプリに関して、セッションIDを含めても危険性は変わらない

正直webアプリでも大して変わらんのでは、と思っているのは内緒である

と思ったので短慮なところ、見落としている視点があるようなら今後のためにご教示をいただきたく

以上、よろしくお願いいたしま

記事への反応(ブックマークコメント)

ログイン ユーザー登録
ようこそ ゲスト さん