【Identity Platform 活用】⑤ Identity Platform を使う上で抑えておきたいセキュリティ知識
1. はじめに
こんにちは、クラウドエース第三開発部の秋庭です。
前回の記事では、Identity Platform のテナント機能でできることについてご紹介しました。
今回は Identity Platform を使用する上でのセキュリティに関する情報について、ご紹介できればと思います。
以下の点については今回の記事で取り扱いませんので、ご了承ください。
- Identity Platform 自体の紹介
- Identity Platform と Firebase Authentication の詳細な比較
2. ID トークン
ID トークンの基礎
ID トークンは、ログインした際に Identity Platform から発行される JWT です。
リクエストに ID トークンを含め、サーバーサイドで検証することでリクエストを認証することができます。
有効期限
ID トークンの期限は 1 時間に設定されています。ログイン時に同時に発行されるリフレッシュトークンを使用して、新しい ID トークンを要求できます。
Web SDK(フロントエンド)では getIdToken() を利用して ID トークンを取得すると、期限が切れている場合に自動で更新を行ってくれます。
リフレッシュトークンは基本的に有効期限がありませんが、revokeToken API を使用して無効化できます。
参考
・Method: accounts.revokeToken | Identity Platform Documentation | Google Cloud
・Go Admin SDK: RevokeRefreshTokens - firebase.google.com/go/v4/auth - Go Packages
・Node.js Admin SDK: BaseAuth.revokeRefreshTokens() | Firebase Admin SDK
・ユーザー セッションの管理 | Firebase Authentication
ID トークンは JWT であるため、窃取された場合、有効期限が切れるまで認証が有効であることに注意してください。
ステートフルな認証を行いたい場合、Identity Platform では前述したリフレッシュトークンの取り消しと、リフレッシュトークン取り消しの検出を組み合わせることで実現することができます。
詳細は弊社唐津の記事をご確認ください
保存場所
発行された ID トークンやリフレッシュトークンの保存先は、以下の 3 つから指定が可能です。
保存先 | 説明 |
---|---|
localStorage or IndexedDB | ブラウザやタブを閉じて、再度開いても状態が維持されます。状態を削除するには、明示的にログアウトの操作を行う必要性があるます。 |
sessionStorage | タブおよびセッションで状態が維持され、タブやウィンドウを閉じると状態はクリアされます。 |
in-memory | メモリ上で状態が維持され、リローディングなど画面の更新があると状態がクリアされます。 |
保存先は、Web SDK(フロントエンド)にて以下のように setPersistence()
の箇所で指定が可能です。
import {
getAuth,
setPersistence,
signInWithEmailAndPassword,
browserSessionPersistence,
} from "firebase/auth";
const auth = getAuth();
// browserLocalPersistence or indexedDBLocalPersistence
// or browserSessionPersistence or inMemoryPersistence
setPersistence(auth, browserSessionPersistence)
.then(() => {
// Existing and future Auth states are now persisted in the current
// session only. Closing the window would clear any existing state even
// if a user forgets to sign out.
// ...
// New sign-in will be persisted with session persistence.
return signInWithEmailAndPassword(auth, email, password);
})
.catch((error) => {
// Handle Errors here.
const errorCode = error.code;
const errorMessage = error.message;
});
公共のスペースでの利用が想定される場合、認証の情報が永続的に保存されるとセキュリティリスクが上がるため、localStorage
よりも sessionStorage
の方が適していると言えます。
一方、多要素認証がユーザーに推奨されている場合、sessionStorage
を指定していると誤ってタブを閉じた際に多要素認証でのログインのやり直しが発生してしまうため、体験が悪くなってしまう可能性があります。
社内など安全な場所での利用が想定される場合、localStorage
が適した選択肢となりそうです。
アプリケーションがどのように使われるかを想定して選択するのがよいと思います。
CSRF XSS 対策
リクエストのヘッダーに ID トークンを付与する場合と、Cookie を付与する場合のセキュリティの違いについて確認します。
session cookie の作成方法
ログインをすることで ID トークン(JWT)が発行されることは既に解説しましたが、Admin SDK(サーバーサイド)or REST API では ID トークンを使用することで session cookie を作成することができます。
参考
・セッション Cookie を管理する | Firebase Authentication
・Method: projects.createSessionCookie | Identity Platform Documentation | Google Cloud
・Go Admin SDK: SessionCookie - firebase.google.com/go/v4/auth - Go Packages
・Node.js Admin SDK: createSessionCookie() | Firebase Admin SDK
項目 | ID トークン(JWT) | Session Cookie |
---|---|---|
保存場所 | localStorage / IndexedDB / sessionStorage / in-memory | Cookie Store |
送信方法 | クライアントが Authorization ヘッダーに含める | ブラウザが自動送信 |
CSRF 対策 | Authorization ヘッダーを使うと CSRF を防げる | SameSite 属性 で防止 |
XSS 耐性 | XSS に弱い(盗まれる可能性あり) | HttpOnly 属性なら XSS 耐性が少し高い(送信されることを防げる訳ではない) |
有効期限 | 1 時間 | 5 分 ~ 14 日(作成時に指定) |
ステートレス/ステートフル | ステートレス(ステートフルに変更可能) | ステートレス(ステートフルに変更可能) |
項目について詳しく見ていきます。
送信方法では、以下のような違いがあります。
- ID トークン: リクエスト毎にヘッダーに付与
- session cookie: リクエスト毎に付与する必要性がない(Cookie の失効毎にバックエンド側で生成して付与)
CSRF に対しては、ID トークンの場合も session cookie の場合も同等であると考えて良さそうです。
XSS に対しては、ID トークンは中身を見られた上で不正なリクエストも送られてしまうと言えます。
HttpOnly 属性を付与した session cookie の場合、cookie の内容を見られることはありませんが、不正なリクエストに認証情報が付与されてしまうという点では同等と言えます。
有効期限は、発行される ID トークンは 1 時間固定となっていますが、session cookie は有効期限を作成時に指定することが可能です。
ステートレスかステートフル化に関しては #有効期限 の項で説明したように、リフレッシュトークンの無効化を検出することでステートフルを実現することが可能となっています。
大きな差はないので、セキュリティ要件に応じて ID トークンか session cookie かを選択するのが良いと思います。
3. アカウントロック
Identity Platform のユーザーには有効/無効、メールアドレス確認済/未確認などの状態がありますが、その他に、ログインに一定数失敗するとどのような操作も受け付けなくなる一時的なアカウントロックのような状態が存在します。
アカウントロックの状態の時にリクエストを送信すると、以下のようなレスポンスが返されます。
アカウントロック状態になると、正しいパスワードを送っても同様のレスポンスが返されるようになってしまいます。
"TOO_MANY_ATTEMPTS_TRY_LATER : Access to this account has been temporarily disabled due to many failed login attempts. You can immediately restore it by resetting your password or you can try again later."
レスポンスメッセージにあるように、この状態になった場合はパスワードをリセットすることでその場でアカウントロック状態が解除され、操作が行えるようになります。
辞書攻撃などから守るためにこのような動作になっていますが、ユーザーがログインのミスで同様のレスポンスを返されることもあると思うので、開発者側はこの仕様を知っておくと良いと思います。
アカウントロックの仕様に関して、2025 年 1 月現在公式ドキュメントに詳しい記載はありません。
2024 年 4 月頃に、挙動について私が動作検証した際の表を以下に記載します。
試行の間隔が短いほど早くアカウントロック状態になり、ログインに失敗し続けるとアカウントロックの時間が伸びていくようです。
比較表
リクエスト回数 | 経過秒数 | 送信したパスワード | レスポンス内容 | ロックされている時間 |
---|---|---|---|---|
1 | 0 | 誤(ったパスワード) | INVALID_PASSWORD | |
2 | 15 | 誤 | INVALID_PASSWORD | |
3 | 30 | 誤 | INVALID_PASSWORD | |
4 | 45 | 誤 | INVALID_PASSWORD | |
5 | 60 | 誤 | INVALID_PASSWORD | |
6 | 75 | 誤 | TOO_MANY_ATTEMPTS_TRY_LATER | ~ 約 30s |
7 | 90 | 誤 | INVALID_PASSWORD | |
8 | 105 | 誤 | TOO_MANY_ATTEMPTS_TRY_LATER | |
9 | 120 | 誤 | TOO_MANY_ATTEMPTS_TRY_LATER | 約 15s ~ 45s |
10 | 135 | 誤 | INVALID_PASSWORD | |
11 | 150 | 誤 | TOO_MANY_ATTEMPTS_TRY_LATER | |
12 | 165 | 誤 | TOO_MANY_ATTEMPTS_TRY_LATER | |
13 | 180 | 誤 | TOO_MANY_ATTEMPTS_TRY_LATER | |
14 | 195 | 誤 | TOO_MANY_ATTEMPTS_TRY_LATER | 約 45s ~ 75s |
15 | 210 | 誤 | INVALID_PASSWORD | |
16 | 225 | 誤 | TOO_MANY_ATTEMPTS_TRY_LATER | |
17 | 240 | 誤 | TOO_MANY_ATTEMPTS_TRY_LATER | |
18 | 255 | 誤 | TOO_MANY_ATTEMPTS_TRY_LATER | |
19 | 270 | 誤 | TOO_MANY_ATTEMPTS_TRY_LATER | |
20 | 285 | 誤 | TOO_MANY_ATTEMPTS_TRY_LATER | |
21 | 300 | 誤 | TOO_MANY_ATTEMPTS_TRY_LATER | |
22 | 315 | 誤 | TOO_MANY_ATTEMPTS_TRY_LATER | |
23 | 330 | 誤 | TOO_MANY_ATTEMPTS_TRY_LATER | |
24 | 345 | 誤 | TOO_MANY_ATTEMPTS_TRY_LATER | |
25 | 360 | 誤 | TOO_MANY_ATTEMPTS_TRY_LATER | |
26 | 375 | 誤 | TOO_MANY_ATTEMPTS_TRY_LATER | |
27 | 390 | 誤 | TOO_MANY_ATTEMPTS_TRY_LATER | |
28 | 405 | 誤 | TOO_MANY_ATTEMPTS_TRY_LATER | 約 180s ~ 210s |
29 | 420 | 誤 | INVALID_PASSWORD | |
30 | 435 | 誤 | TOO_MANY_ATTEMPTS_TRY_LATER |
リクエスト回数 | 経過秒数 | 送信したパスワード | レスポンス内容 | ロックされている時間 |
---|---|---|---|---|
1 | 0 | 誤 | INVALID_PASSWORD | |
2 | 60 | 誤 | INVALID_PASSWORD | |
3 | 120 | 誤 | INVALID_PASSWORD | |
4 | 180 | 誤 | INVALID_PASSWORD | |
5 | 240 | 誤 | INVALID_PASSWORD | |
6 | 300 | 誤 | INVALID_PASSWORD | |
7 | 360 | 誤 | INVALID_PASSWORD | |
8 | 420 | 誤 | TOO_MANY_ATTEMPTS_TRY_LATER | ~ 120s |
9 | 480 | 誤 | INVALID_PASSWORD | |
10 | 540 | 誤 | TOO_MANY_ATTEMPTS_TRY_LATER | |
11 | 600 | 誤 | TOO_MANY_ATTEMPTS_TRY_LATER | 60s ~ 180s |
12 | 660 | 誤 | INVALID_PASSWORD | |
13 | 720 | 誤 | TOO_MANY_ATTEMPTS_TRY_LATER | |
14 | 780 | 誤 | TOO_MANY_ATTEMPTS_TRY_LATER | |
15 | 840 | 誤 | TOO_MANY_ATTEMPTS_TRY_LATER | |
16 | 900 | 誤 | TOO_MANY_ATTEMPTS_TRY_LATER | |
17 | 960 | 誤 | TOO_MANY_ATTEMPTS_TRY_LATER | |
18 | 1020 | 誤 | TOO_MANY_ATTEMPTS_TRY_LATER | 300s ~ 420s |
19 | 1080 | 誤 | INVALID_PASSWORD | |
20 | 1140 | 誤 | INVALID_PASSWORD |
リクエスト回数 | 経過秒数 | 送信したパスワード | レスポンス内容 | ロックされている時間 |
---|---|---|---|---|
1 | 0 | 誤 | INVALID_PASSWORD | |
2 | 10 | 誤 | INVALID_PASSWORD | |
3 | 20 | 誤 | INVALID_PASSWORD | |
4 | 30 | 誤 | INVALID_PASSWORD | |
5 | 40 | 誤 | INVALID_PASSWORD | |
6 | 50 | 誤 | TOO_MANY_ATTEMPTS_TRY_LATER | |
7 | 60 | 誤 | TOO_MANY_ATTEMPTS_TRY_LATER | |
8 | 70 | 誤 | TOO_MANY_ATTEMPTS_TRY_LATER | |
9 | 80 | 誤 | TOO_MANY_ATTEMPTS_TRY_LATER | |
10 | 90 | 誤 | TOO_MANY_ATTEMPTS_TRY_LATER | 40s ~ 60s |
11 | 100 | 誤 | INVALID_PASSWORD | |
12 | 110 | 誤 | TOO_MANY_ATTEMPTS_TRY_LATER | |
13 | 120 | 誤 | TOO_MANY_ATTEMPTS_TRY_LATER | |
14 | 130 | 誤 | TOO_MANY_ATTEMPTS_TRY_LATER | |
15 | 140 | 誤 | TOO_MANY_ATTEMPTS_TRY_LATER | |
16 | 150 | 誤 | TOO_MANY_ATTEMPTS_TRY_LATER | |
17 | 160 | 誤 | TOO_MANY_ATTEMPTS_TRY_LATER | |
18 | 170 | 誤 | TOO_MANY_ATTEMPTS_TRY_LATER | 60s ~ 80s |
19 | 180 | 誤 | INVALID_PASSWORD | |
20 | 190 | 誤 | TOO_MANY_ATTEMPTS_TRY_LATER |
4. メールアドレスの列挙保護
Identity Platform は、メールアドレスの列挙保護機能により、ブルートフォース攻撃対策を提供しています。
無効の場合、ログイン時にメールアドレスが間違っていた際、EMAIL_NOT_FOUND
が返されますが、攻撃者はレスポンスからメールアドレスが使用されているかどうかを推測できます。
列挙保護が有効になっている場合、INVALID_LOGIN_CREDENTIALS
が返されるようになり、レスポンスからメールアドレスが使用されているか判別できないようになります。
2025 年 1 月現在、この機能はプロジェクト作成時にデフォルトで有効になっています。
参考
・メール列挙保護を有効または無効にする | Identity Platform Documentation | Google Cloud
5. データの保持リージョン
2025 年 1 月現在、Firebase Authentication および Identity Platform では、データの保存リージョンを選択できません。
保存先はアメリカ国内のリージョンに固定となるため、日本国内にデータを保管する必要がある場合は注意が必要です。
6. API キーの権限
Firebase Authentication および Identity Platform の利用を開始した際に API 実行に必要な API キーが作成されます。
![]() |
API キーは例として、Web SDK(フロントエンド)で以下のように初期化に使用されます。
const firebaseConfig = {
apiKey: "AIza******",
authDomain: "****.firebaseapp.com",
};
const app = initializeApp(firebaseConfig);
Identity Platform のみを使用する場合、初期状態では API キーに過剰な権限が付与されていることがあります。
![]() |
Identity Platform のみに使う API キーであれば、以下の API を選択すれば動作します。
- Identity Toolkit API
- Token Service API
![]() |
必要に応じて、API キーにサービスに必要な API を追加してください。
フロントエンドで初期化に使用されていることから分かる通り、この API キーは露出しています。
意図しない API へのアクセスを防ぐため、事前に API キーの権限を絞っておくことをお勧めします。
参考
・弊社記事: Firebase の API キーは公開しても大丈夫?
7. テナントアクセスのコントロール
IAM を利用して、テナントの情報にアクセスできるプリンシパルを制限することができます。
詳細は前回の記事をご参照ください。
8. ログ
Identity Platform では、ユーザーのアクティビティを「アクティビティロギング」で記録できます。
管理者の操作ログは「監査ログ」を使用して記録することができます。
参考
・アクティビティ ロギング | Identity Platform Documentation | Google Cloud
・Identity Platform の監査ロギング | Identity Platform Documentation | Google Cloud
9. 準拠しているセキュリティ規格
Firebase Authentication および Identity Platform は以下のセキリティ規格に準拠しています。
- ISO 27001
- ISO 27017
- ISO 27018
参考
・ISO と SOC への準拠
10. おわりに
Identity Platform を使用する上で知っておくとよいセキュリティ関連の知識について、今回の記事でご紹介しました。
この記事が、IDaaS 導入の際の検討の一助になれば幸いです。
ここまで読んで頂き、ありがとうございました。
Identity Platform 関連記事
Discussion