※追記: 本記事の続編としてin-memory方式からアクセストークンを奪取するPoCを下記記事で公開しました。ぜひあわせてご覧ください。
はじめに
こんにちは。 セキュリティエンジニアの@okazu-dm です。
この記事では、Auth0のSPA SDKでアクセストークンのキャッシュを有効化する際の考慮ポイントについて紹介し、それを切り口にアクセストークンの保存場所に関してin-memory方式とlocalStorage方式の2つについて解説します。
Auth0のようなIDaaSは昨今かなり普及が進んでいると思いますが、Flatt Securityの提供するセキュリティ診断はAuth0に限らずFirebase AuthenticationやAmazon CognitoなどのIDaaSのセキュアな利用まで観点に含めて専門家がチェックすることが可能です。
ご興味のある方は是非IDaaS利用部分を含めたセキュリティ診断を実施したSUSTEN様の事例インタビューや、Firebase Authentication、Amazon Cognitoのセキュリティ観点を紹介した他のブログ記事もご覧ください。
Auth0について
まず、Auth0について簡単に紹介します。
Auth0はAuth0社によって開発されたIDaaSです。 Open ID Connectプロバイダとしての利用が可能で、ID管理だけでなくロールベースのアクセス制御やMFAなどの機能も提供されており、アプリケーションから利用するためのSDKも様々な言語、フレームワークを対象に用意されています。
Auth0におけるアクセストークンのストレージ
Auth0のSPA SDKを利用している場合、アクセストークンの保存方法としてメモリ上に一時的に保存する手法とlocalStorageに永続化する手法、2つの選択肢があります。
デフォルトの挙動としてはアクセストークンを永続化せず、ブラウザのメモリ空間上にのみ保存します。この記事では、この方式をin-memory方式と呼びます。
次に、localStorageにアクセストークンを保存する手法です。この記事では、この方式をlocalStorage方式と呼びます。
これは以下のドキュメントのように、クライアントの初期化時に渡すオプションの cacheLocation
プロパティを localstorage
に指定することで有効になります。
共通する一般的なセキュリティ対策として
- アクセストークンの利用期限を短くすること
- アクセストークン自体の権限を必要最低限にすること
が挙げられますが、これについてはAuth0においても同じです。
どちらを選択するか
上述のように、Auth0はデフォルトではin-memory方式を採用しています。
in-memory方式の場合、アクセストークンが永続化されません(cookieやlocalStorageなどにデータを保存しない)。これは具体的には、アクセストークンを取得したタブ(またはウィンドウ)でのみ、そのアクセストークンが使用可能である、という意味です。
そのため、サービスのユーザーがタブを開く度にアクセストークンの取得処理が走るというデメリットがあります。
そのため開発者に対して、以下のケースなどでlocalStorage方式を採用するインセンティブが働きます。
- Auth0側へのリクエスト数を減らしてrate limitを回避したい場合
- 新しいタブを開いた際にアクセストークンの取得処理をスキップすることで、コンテンツの読み込み完了までの時間を短縮するなど、ユーザーの体験を改善したい場合
rate limitについて補足しますが、記事執筆時点でAuth0のRate limit policyのページを確認した限り、無償利用のテナントは1分あたり300リクエストの制限があります(具体的な制限対象は公式ドキュメントを参照)。
以上から、それぞれのメリット・デメリットを把握した上でローカルストレージにアクセストークンを永続化するかどうかを検討する必要があります。
in-memory方式とlocalStorage方式の比較
ここでは、セキュリティの観点からそれぞれの手法の差をより検討していきます。
まず、Auth0の公式ドキュメント 上でそれぞれの手法について書かれている箇所を見ていきます。
Auth0のドキュメントではin-memory方式を「most secure option」として推奨している一方で、localStorageについては以下のように触れられています。
トークン(アクセストークン)をlocalStorageに保存する手法は、ページの更新や別のタブを開いてもトークンを永続化することを可能にするが、XSSが可能な場合は、攻撃者がlocalStorage内のトークンを取得可能になる。 XSSを可能にする脆弱性は、SPAのソースコード、またサードパーティのJavascriptコードのいずれかの中に存在する可能性がある
(筆者による日本語訳)
この部分については、XSSが実際に可能な場合はlocalStorage内のアクセストークンを取得可能なので正しいと考えられます。
次に、in-memory方式を選択することがどの程度安全なのかについて検討します。
攻撃者がXSSで任意のコードを実行することが可能なら、SPAがアクセストークンを取得する前後の処理も上書きすることも可能であると考えられます。そのため、結論としては「少なくともXSSからトークンを保護することはできない」と言えます。
ただし、localStorageの内容を機械的に抜き出すよりも、アプリケーションの仕組みに応じた攻撃が必要になるため、攻撃の難易度は多少差があるとも言えます。
補足すると、Auth0は明示的にドキュメント内でin-memory方式についての記述中でXSSについて言及はしていません。しかし、localStorageについての記述中でXSSに対して脆弱である、という記述があるため、in-memory方式は逆にXSSの対策として有効である、という主張だと判断しました。
このように、Auth0のドキュメントではin-memory方式を推奨していますが、筆者が検討した限り、どちらの方法においてもフロントエンドでアクセストークンを直接扱う以上、アクセストークンを完全に保護することは難しく、利便性とサービス側のユースケースに応じてどちらを採用しても良い程度の差だと感じました。
以上から、この2つの方法を比較した際にセキュリティ的な側面からの実質的な差はないと言えます。
余談ですが、似た話題としてセッションIDやトークンの保存場所としてのlocalStorageとCookie、それぞれの長所と短所について触れた、徳丸浩さんのスライドでは「CookieとlocalStorageはどちらが安全とは言えず一長一短」「適材適所で使えば良い」と書かれています。
同様に、今回紹介したAuth0のアクセストークンの扱いも挙動の差を把握し、サービスに適した方法を選択することが重要と考えます。
まとめ
この記事では、Auth0のアクセストークン保存場所としてlocalStorageを選択する手法を紹介し、メモリ上に保存する手法とそれぞれの挙動の違い、考慮すべき点について検討しました。
冒頭で紹介したように、Flatt Securityではセキュリティエンジニアが手動で検査を行うセキュリティ診断サービスを提供しています。IDaaSの利用に関する診断も可能ですし、AWS・GCP・Azure等のパブリッククラウドその他のサービスをセキュアに扱えているか合わせて診断することも可能です。
診断プランは柔軟に様々な形が組めますが、上記のデータが示すように、診断は幅広いご予算帯に応じて実施が可能です。ご興味のある方向けに下記バナーより料金に関する資料もダウンロード可能です。
また、Flatt Securityはセキュリティに関する様々な発信を行っています。 最新情報を見逃さないよう、公式Twitterのフォローをぜひお願いします!
ここまでお読みいただきありがとうございました。