- Date
SPAでの主要IDaas比較まとめ
- Share on Hatena
- Share on X
- Share on Facebook
目次
JWT(JSON Web Token)とは何か SPA と JWT JWT 保存先の候補 Cookie Local Storage Session Storage In Memory IDaas 比較 AWS Cognito 特徴 実装方法 内部実装の詳細 Auth0 特徴 実装方法 内部実装の詳細 Firebase Authentication 特徴 内部実装の詳細 まとめ 参考会社で Auth0 を導入する機会があり、他のサービスも比較してまとめました。
JWT(JSON Web Token)とは何か
JWT とは、JSON 形式で表現された認証情報などを URL 文字列などとして安全に送受信できるよう、符号化やデジタル署名の仕組みを規定した標準規格。IETF によってRFC 7519として標準化された文字列の形式です。
encode token
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
decoded token
# header { "alg": "HS256", "typ": "JWT" } #payload { "sub": "1234567890", "name": "John Doe", "iat": 1516239022 }
SPA と JWT
コードを静的にホスティングしている SPA の場合、MPA(Multiple Page Application)では、httpOnly 属性&sameSite 属性で認証用の cookie をつけるのが王道パターンが使えません。
JWT の有効期間が切れた後に再度ログイン画面を表示する必要があり、JWT が切れるたびにログイン情報を入力させます。
一方 JWT の有効期間を長くすれば危険で、短くすれば UX が犠牲になります。JWT の認証トークンを保存 or 再発行に工夫が必要です。
JWT 保存先の候補
Cookie
CGI スクリプトのようなサーバ側コネクションにより、クライアント側に情報を保存させ、そしてそれを使うことができます。4096byte まで設定可能。
httpOnly 属性 false なら JavaScript でも操作でき、true なら JavaScript で操作できません。
https://www.futomi.com/lecture/cookie/specification.html
デメリット
- 同一ドメインで API をホストしていないと httpOnly 属性&sameSite 属性がつけられません。
- XSS 脆弱性、CSRF 対策は必要です。
Local Storage
Web ブラウザ(すなわちブラウザのユーザー)が JavaScript を用いて任意の情報を保存できる仕組みです。実用上の local storage は、巨大な JavaScript オブジェクト。
あらゆる JavaScript コードから自由にアクセスでき、データをアタッチも、削除もできます。
デメリット
- XSS 脆弱性対策は必要
Session Storage
Local Storage とほぼ同じ。Local Storage に保存されたデータに期限がないが、Session Storage に保存されたデータはページのセッションが終了するときに消去されます。
ただしブラウザを開いている限り、ページの再読み込みや復元を越えて持続。新しいタブやウィンドウにページを開くと、新しいセッションが開始します。
In Memory
JavaScript でブラウザのメモリ内に認証トークンを保存するというやり方。例えばクロージャーみたいなものを作ってそこに入れるなど、いろいろ方法はあります。
デメリット
- タブ間でもログイン状態が続かないので永続性がありません
IDaas 比較
「Identity as a Service」の略であり、クラウド経由で ID 認証ならび ID パスワード管理、シングルサインオン (SSO)、アクセス制御などを提供するサービス。
サービスの仕様にあうなら、IDaas を導入すれば実装コストを削減できます。それぞれサービスごとの仕様を確認しました。
AWS Cognito | Auth0 | Firebase | |
---|---|---|---|
保存方法 | session storage / local storage | in memory / local storage | indexedDB |
実装しやすさ | △ | ○ | ○ |
拡張性 | ○ | ○ | △ |
セキュリティ | △ | ○ | △ |
価格 | ○ | × | ○ |
準拠法 | ○ | ○ | ○ |
AWS Cognito
AWS が提供しているサービスです。 パスワード、電話番号、一般的なフェデレーション ID プロバイダ(Google、Facebook、Twitter)などを使用した認証ができます。
特徴
- 大規模サービスで採用事例が多い
- メールにカスタムパラメーターの埋め込み可能
- OIDC, SAML と MFA 対応
- ユーザーの必須属性が設定できる
- ユーザープールは一度作ると属性変更できない
- カスタマイズ属性追加や細かい設定が可能
- カスタマイズ性が高い分、設定が複雑
- 無料枠:50,000 MAU、従量課金枠:50,001 ~ 100,000 MAU: 0.0055USD
実装方法
amazon-cognito-identity-js の使用が推奨されています。
内部実装の詳細
デフォルトは refresh token もふくめて全部 Local Storage に保存します。Session Storage にも変えられます。access token を取り出すたびに 有効期限を検証し、期限切れの場合は refresh しています。
When using Authentication with AWS Amplify, you don't need to refresh Amazon Cognito tokens manually. The tokens are automatically refreshed by the library when necessary.
Authentication - Password & user management - JavaScript - AWS Amplify Docs
- https://github.com/aws-amplify/amplify-js/blob/amazon-cognito-identity-js%405.2.9/packages/amazon-cognito-identity-js/src/CognitoUser.js#L1396
- https://github.com/aws-amplify/amplify-js/tree/aws-amplify%401.1.19/packages/core/src/Credentials.ts#L197
2019 年以前からセキュリティを高めるため local storage をやめる issue があげられてますが、進んでいません。
All cognito session tokens id, access and refresh tokens are being persisted into localstorage. This goes against all industry security best practice of storing sensitive information in signed httponly cookies.
To see why its bad practice this article presents a summary.
Sensitive information are being persisted in local storage #3436
Auth0
特徴
- カスタマイズ性が高い
- セキュリティレベルも高い
- 大規模サービスで採用事例が多い
- 料金が高い
実装方法
フレームワークごとにライブラリがあります。かなり簡単です。
- https://www.npmjs.com/package/@auth0/auth0-vue
- https://www.npmjs.com/package/@auth0/auth0-react
- https://www.npmjs.com/package/@auth0/nextjs-auth0
内部実装の詳細
ドキュメントも充実しており、下記を読めば大体概要が把握できます。
Single-Page Applications (SPA) with API
処理の流れは大きく 2 ステップです。
- 見えない iframe 要素を作って、iframe の中で Auth0 のサーバーと通信してメッセージを受信。
- それに含まれるレスポンスからアクセストークンを In Memory に展開し返す。
出典: Solution Overview (SPAs + API)
iframe でのメッセージ受信についてはこちらを参照ください。
Auth0 に対して有効な session を持っている限り、自動的にトークンが更新されます。
https://github.com/auth0/auth0.js/blob/v9.19.0/src/web-auth/index.js#L543
You can make a silent authentication request to get new tokens as long as the user still has a valid session at Auth0. The checkSession method from auth0.js uses a silent token request in combination with response_mode=web_message for SPAs so that the request happens in a hidden iframe.
https://auth0.com/docs/authenticate/login/configure-silent-authentication#renew-expired-tokens
Auth0 の SPA ライブラリはリフレッシュトークンを使ったアクセストークン再発行処理を Web Worker に隔離。XSS に対してもアクセストークンの取得はできても、リフレッシュトークンは取得できない仕組みになっています。
https://auth0.com/blog/secure-browser-storage-the-facts/
Firebase Authentication
GCP が提供している Firebase という mBaas の 1 つ。 パスワード、電話番号、一般的なフェデレーション ID プロバイダ(Google、Facebook、Twitter)などを使用した認証ができる。
特徴
- 電話認証使わなければ基本無料
- 一部のオペレーションで上限 を超えた場合従量課金
- 採用事例が多い
- カスタマイズ性は低くユーザー情報は最低限
- メールにカスタムパラメーターの埋め込み可能
- 設定が簡単
- 準拠法は日本に変更可
内部実装の詳細
IndexedDBを使ってるらしいですが、細かいところまで調べられませんでした。わかったら教えてください。
まとめ
XSS 脆弱性があったとしても、リフレッシュトークンの奪取ができない Auth0 が優れていると言えそうです。
ただ Auth0 は MAU 単位の課金で、月額 3 ~ 20 円かかります。基本有料会員のみのビジネスならおすすめです。もし無料会員がたくさんいると、売上を圧迫する可能性があります。
要件にあわせて選ぶと良いでしょう。
参考
- SPA セキュリティ入門~ PHP Conference Japan 2021
- Web アプリケーションで JWT をセッションに使う際の保存先は(自分なりに説明できれば)どちらでもよいと思います
- どうしてリスクアセスメントせずに JWT をセッションに使っちゃうわけ? - co3k.org
- JWT 形式を採用した ChatWork のアクセストークンについて - Chatwork Creator's Note
- Stop using JWT for sessions
- @auth0/nextjs-auth0 と @auth0/auth0-react の使い分け
- JWT を使った今どきの SPA の認証について
- Share on Hatena
- Share on X
- Share on Facebook