SPAセキュリティ入門
https://scrapbox.io/files/615951cec172d1001fadffa0.png
https://scrapbox.io/files/615951e7d11b7300247ec83c.png
ネットでの議論
https://scrapbox.io/files/61595236180a45001d145859.png https://scrapbox.io/files/6159525a1cb63e001dfae27c.png
https://scrapbox.io/files/61595268c88147001d448256.png
SPAとは
https://scrapbox.io/files/615952db60f178001d70893b.png
https://scrapbox.io/files/61595302972fc4001def91f9.png
https://scrapbox.io/files/615953356143f1001f7fb432.png
https://scrapbox.io/files/6159534fc270fc0022c075df.png
SPAとCORS
https://scrapbox.io/files/615953985f1405002336ee4c.pnghttps://scrapbox.io/files/615954071680db001f6d0ed5.png
corsは水際対策。cookieがなければ大きな問題にはなりにくい
https://scrapbox.io/files/6159542ff62d01001d0f25d2.png
現在のフレームワークは?
https://scrapbox.io/files/61595483fd315b001d07299d.png
https://scrapbox.io/files/615954b7b802eb001dc6275c.png
https://scrapbox.io/files/615954f4e2b8df001d14709a.png
ヘッダトークンの場合は、CORS不備でもなりすましは問題ない
https://scrapbox.io/files/6159556963dedb0023c99568.png
Firebase ReST APIで学ぶJWT
https://scrapbox.io/files/61595586972fc4001def9ba0.png
https://scrapbox.io/files/615955ace2b8df001d14742c.png
https://scrapbox.io/files/615955e8353a790023349d36.png
Firebase Authnでは色々使えるよ
https://scrapbox.io/files/6159563632564f00205f9bb9.png
https://scrapbox.io/files/6159565232564f00205f9bf9.png
署名がなかった認証トークンのケース -> 7pay(の元々の原因ではなかったけど)
そうするとアプリ内の操作をするトークンが発行されてた
https://scrapbox.io/files/61595877721fe300210a5c42.png
Firestoreから帰ってきたID tokenを使うhttps://scrapbox.io/files/6159594b63dedb0023c9abb4.png
https://scrapbox.io/files/61595939180a45001d148a02.png
JWTのタイムアウトとリフレッシュとセッション
https://scrapbox.io/files/615959c7cc2a8200236e3d18.png
https://scrapbox.io/files/615959cb31cf24001d041e5f.png
https://scrapbox.io/files/615959f33db6c8001dffa703.png
https://scrapbox.io/files/61595a0e4d15c2001dbe63c2.png
https://scrapbox.io/files/61595a12a0a3ae001de2fd67.png
https://scrapbox.io/files/61595a2ac88147001d449d5d.png
Firebaaseのログアウトはどうする
https://scrapbox.io/files/61595a7ba0a3ae001de301a0.png
https://scrapbox.io/files/61595b255f140500233704d6.png
なぜトークンを取り消したいのか -> 悪用されるチャンスがあるから。でもステートレスなトークンは有効のままであるhttps://scrapbox.io/files/61595b4f10c458001dd124e6.png
。https://scrapbox.io/files/61595b375e4459001d5d3864.png
https://scrapbox.io/files/61595b6b048814001d4ec2c9.png
https://scrapbox.io/files/61595b765f140500233705bb.png
https://scrapbox.io/files/61595bb9c88147001d44a847.png
https://scrapbox.io/files/61595bc31cb63e001dfb0efd.png
https://scrapbox.io/files/61595c2c1cac0500238ce66c.png
https://scrapbox.io/files/61595c256eb57f001d7baf52.pnghttps://scrapbox.io/files/61595c65972fc4001defcbf6.png
https://scrapbox.io/files/61595c78972fc4001defcc49.png
https://scrapbox.io/files/61595cb90a62c5001d7ea46a.png
https://scrapbox.io/files/61595d02353a79002334cc0c.png
SPAの脆弱性
XSS
https://scrapbox.io/files/61595d3efc192a00230e71c4.png
https://scrapbox.io/files/61595d876143f1001f80049a.png
https://scrapbox.io/files/61595dad27bce80023353352.png
APIとJSそれぞれXSSの可能性があるが、発生箇所による脅威が違う
https://scrapbox.io/files/61595de8ca5aef00230dbf84.png
https://scrapbox.io/files/61595e29d2d90f001d820c20.png
https://scrapbox.io/files/61595e6a6e912b001dd11fdd.png
https://scrapbox.io/files/61595e88c5edcd00236c43af.png
https://scrapbox.io/files/61595eafe2b8df001d149ce9.png
https://scrapbox.io/files/61595ebc6ef450001d689183.png
CSRF
https://scrapbox.io/files/61595efcc172d1001fae3e19.png
https://scrapbox.io/files/61595f24d11b7300247f0671.png
https://scrapbox.io/files/61595f34c5edcd00236c49cf.png
https://scrapbox.io/files/61595f46a0a3ae001de3362d.png
https://scrapbox.io/files/61595f8560f178001d70d1d0.png
https://scrapbox.io/files/61595f9023f0d300230bbb1b.png
https://scrapbox.io/files/61595f9f2c7a24001d6c812b.png
https://scrapbox.io/files/61595fc44d15c2001dbe853c.png
https://scrapbox.io/files/61595fdd40c4ec0023312ade.png
https://scrapbox.io/files/61595ff3dfa34c001d105f9b.png
https://scrapbox.io/files/61596002417c5900218474f8.png
https://scrapbox.io/files/6159602dd2d90f001d821689.png
Discord上のQ& A
QA
質問者
(質問者A) トークありがとうございました。とても面白かったです。ズレた質問だったら恐縮です。
Cookies を、HttpOnly 属性を true にせずに、API サーバーにそのまま認証情報として送ることを前提と しない 単なる SPA のためのクライアント側のストアとして利用する場合 (そして、API サーバーへのリクエストはリクエストヘッダの Bearer で行う場合) 、クライアントと API サーバー間の通信に、説明いただいた cookies 起因の脆弱性は発生しない。しかし、LocalStorage と同様に XSS などの脆弱性の懸念はある、という認識でいます。
この認識が正しいのであれば、それはつまり、LocalStorage が適材適所として許容されるような場面では、cookies に JWT を保存し、SPA の JavaScript から直接その読み書きを行う、というやり方も同じく許容できる、という理解で問題ないでしょうか?
質問背景としては、SPA で認証を要するページを server-side rendering する要件がある場合、rendering を行うサーバー (通常はクライアントの web と同一ドメイン・同一サーバー) にブラウザから JWT を送る必要があり、そのときに JWT による SPA のページの制御をクライアントサイドとサーバーサイドで (isomorphicな実装として) 透過的に行う場合に cookies が便利に利用できるためです。
(回答者)
localStorageとCookieの比較は「論争への答え」としてあげたもので、結局の所XSSそのものを対策するしかない、ということで、結論としてはありではないでしょうか。ただ、脆弱性診断で指摘される可能性は大きいと思いますがw
最近、そういう実装をよく見かけまして、おそらくSSR対応のためだろうと思っておりましたが、やはりそういう事情なのですね。
乱入者(元の質問者への質問)
ちなみに乱入者はOIDCのエヴァンジェリスト
JWTをaccess tokenとして利用する場、有効期限を非常に短くしつつ適宜refreshできるようにするというのがセオリーなのですが、任意のタイミングでのSSRにJWTをJSでつけたくないからCookieを使うというケースにおいて、SSRが必要なタイミングでJWTがまだ有効かどうかJSでチェックしつつ適宜refreshするという実装が必要になると、Cookieを使うメリットはあるでしょうか?
必要以上にJWTの有効期限を長くしなきゃいけなくなったりしたら本末転倒だなと思いまして。
質問者
明確に質問を理解できているかちょっと不安なのですが、そもそも cookie しかサーバーへ届かないので、SSR で JWT をベースに画面をレンダリングしようとすると事実上 cookie しか使えません。
Cookie を使わない場合は、例えば React なら useEffect なんかのクライアントサイドのライフサイクルでやるしかないですよね。
なのでこれは実装次第というか、SSR の段階でレンダリングさせるべきかという要求仕様と、どれだけ SSR を意識しない設計にすべきかの話になってくると思います。
メリットが薄れる、というか余計に実装がややこしくなる可能性ももちろんあり、その場合は pros/cons 判断でクライアント JS だけでやるか、というのもあると思います。
実際に、セオリーを重視したりするとメリットより複雑性などの方が目立つので、自分が関わっている案件だと大体 Next.js を SSR 付きのフロントエンドに使うんですが、現実的には cookies 含めクライアントに JWT を保存することはほぼしておらず、Next.js のサーバーサイドと認証サーバーを使った伝統的なセッション管理ベースで、必要に応じて都度 JWT を問い合わせるようなパターンが多いです。
乱入者
現実的には cookies 含めクライアントに JWT を保存することはほぼしておらず、Next.js のサーバーサイドと認証サーバーを使った伝統的なセッション管理ベースで、必要に応じて都度 JWT を問い合わせるようなパターンが多いです。
QA
(質問)トークありがとうございました。質問なのですが、jwtのペイロードにuser情報(例えば管理者ユーザーのようなユーザ種別)を入れてSPA側でjwt内のユーザー情報を表示(あるいは表示内容の切り替え)を行うのか、あくまでjwtは認証・認可程度にとどめて、ユーザー情報などは別途APIを用意するのかどちらの方が良いのでしょうか?
(回答)ユーザ種別やメールアドレスなどは変更の可能性があるので、都度問い合わせるべきだと思います。