Flatt Security Blog

株式会社Flatt Securityの公式ブログです。プロダクト開発やプロダクトセキュリティに関する技術的な知見・トレンドを伝える記事を発信しています。

株式会社Flatt Securityの公式ブログです。
プロダクト開発やプロダクトセキュリティに関する技術的な知見・トレンドを伝える記事を発信しています。

Firebase Authentication 7つの落とし穴 - 脆弱性を生むIDaaSの不適切な利用

はじめに

こんにちは、株式会社 Flatt Security セキュリティエンジニアのぴざきゃっと (@pizzacat83) です。

認証機構を自作せずに導入できる Firebase Authentication は様々なアプリケーションにて利用されていますが、その特性を十分に理解せずに導入すると、実は不具合や脆弱性が生じることがあります。そこで本稿では Firebase Authentication を利用するうえで、注意しなければ不具合や脆弱性に繋がりうる 7 個の「落とし穴」について解説します。

IDaaS の利点と欠点

多くの Web・スマホアプリはユーザーごとにサービスを提供するために認証機構を持っていますが、認証機構に不備があると個人情報の漏洩や不正な書き換えなど、重大なリスクに繋がる場合もあります。セキュアに認証機構を実装するための注意点は NIST SP 800-63BOWASP ASVS V2 などで解説されているほか、本ブログでもログイン機能の仕様にまつわる観点について過去にご紹介しました。 しかしながらこれらの資料の膨大さから感じられるように、瑕疵なく認証機構を実装することは困難です。

IDaaS (Identity as a Service) は認証機構を API として提供するクラウドサービスで、開発者は IDaaS を利用することでアプリケーションに認証機構を容易に導入できます。一般の開発者が認証機構を自力で実装するよりも、認証機構に特化して作られた IDaaS を利用したほうが安全そうに思われるかもしれません。

ところが IDaaS を導入することにより、逆に脆弱性が生まれることもあります。というのも、IDaaS は特定のアプリケーションのために作られたものではなく、様々なアプリケーションで利用できる汎用的なサービスです。このため IDaaS の仕様や設定値次第では、アプリケーションの仕様に適さない操作をユーザーが勝手に実行できる場合があります。認証機構を自作する場合ではアプリケーションが要求する仕様に沿って認証機構を実装するため、このような問題は IDaaS を利用するアプリケーション特有のものと言えます。アプリケーションに IDaaS を導入する際は、IDaaS の仕様を十分に把握したうえで、アプリケーションに適した設定値を吟味したり、アプリケーションの仕様に適さない IDaaS の機能に関する対策を施したりする必要があります。

本稿では IDaaS の 1 つである Firebase Authentication を取り上げます。Firebase Authentication は他の IDaaS と比べて設定項目が少ないという特徴があります。一見「設定項目が少ないため設定ミスが起きにくく安全」と思われるかもしれませんが、設定項目がないということは、自作した認証機構や他の IDaaS であれば自分のアプリケーションの仕様に合わせてカスタマイズできるのに、Firebase Authentication では自分のアプリケーションをよく知らない Firebase 側が勝手に決めた設定値で固定されていると解釈できます。また設定項目が少ないことにより、Firebase Authentication においてユーザーにどんな操作ができるのかを、開発者がよく理解しないまま導入してしまう可能性が高いです。例えば「自己サインアップ (後述) を許可しますか?」という設定項目があれば、開発者は自己サインアップという機能の存在を認識し、アプリケーションに自己サインアップ機能が必要か判断して設定をするでしょうが、設定項目がない Firebase Authentication では開発者が自己サインアップという機能の存在に気づくきっかけがありません。リファレンスを隅々まで、自分のアプリケーションに無関係な部分を含めて読まない限り、開発者はユーザーに何ができるかを把握しきれないのです。Firebase Authentication は設定項目が少ないことにより、見えないところにいくつものリスクが隠れています。本稿ではそういった「見えない落とし穴」7 つに光を当て、その穴を塞ぐ対処方法について解説していきます。

なお他に知られた IDaaS としては Amazon CognitoAuth0 などが挙げられます。Cognito をセキュアに使うための注意点については以下のブログで解説しておりますので、こちらもぜひご一読ください。

落とし穴 1. 自己サインアップ

ユーザーの新規作成を利用者自身が行うのではなく、管理者がユーザーを発行するようなアプリケーションにおいて Firebase Authentication を導入する場合は、自己サインアップの対策が必要です。

Firebase Authentication では、たとえユーザー登録画面を実装していなかったとしても、createUserWithEmailAndPassword 関数1 などを用いて誰でも勝手にユーザーを作成できます。このことを本稿では自己サインアップ2と呼びます。

ユーザー登録画面が実装されていないアプリケーションにおいて、勝手にユーザーを作成できることは意外に思われるかもしれません。「アプリケーションの仕様に適さない操作をユーザーが勝手に実行できる」という IDaaS の落とし穴の理解を助けるため、その方法を簡単にご説明します。

例として、ログイン画面はあるがユーザー登録画面がない社内システムのようなアプリケーションを考えます。

ユーザー登録に用いる createUserWithEmailAndPassword 関数は Identity Toolkit API における /identitytoolkit/v3/relyingparty/signupNewUser API に対応しており、この API に直接 HTTP リクエストを送信することでユーザーを作成します。リクエストには API キーを付与する必要がありますが、この API キーは例えば次のようにして取得できます。

まずログイン画面を開きます。ここで開発者ツールのネットワークタブを開いたうえで、適当な認証情報を入力して送信します。

ログイン画面と開発者ツールのスクリーンショット。Identity Toolkit API へのリクエストにおいて、URL のクエリー中に API キーが記載されている。

ログイン試行によって Identity Toolkit API にリクエストが送信されます。開発者ツールでこのリクエストを確認すると、上図に示したように URL のクエリーに API キーが記載されています。

こうして取得した API キーを用いて次のようなリクエストを送信すればユーザーが作成され、リクエストで指定したメールアドレスとパスワードでログインが可能となります。

curl -X POST \
  -H 'Content-Type: application/json' \
  --data-binary '{
    "email": "fuga@example.com",
    "password": "silly3demurrer6root2barkeep",
    "returnSecureToken": true
  }' \
  'https://www.googleapis.com/identitytoolkit/v3/relyingparty/signupNewUser?key={API キーをここに書く}'

アプリケーション内で利用していない Firebase Authentication の機能であっても、API を直接呼び出すことで勝手に実行できる、ということはご理解いただけましたでしょうか。ユーザー登録だけでなく、Firebase Authentication の他の機能についても同様のことが可能です。

ここまで読んで「API キーを知られないようにするにはどうすれば良いか」とお考えかもしれませんが、Firebase において API キーは機密情報ではありません。API キーは単に「どの Firebase プロジェクトに関するリクエストなのか」を Firebase が判断するための識別符号に過ぎず、むしろフロントエンドから Firebase にアクセスするために必要不可欠なものです。したがって自己サインアップ等の対策は、API キーが攻撃者に知られていることを前提に行う必要があります。具体的な対策方法については、リスクの解説の後にご説明します。

リスク

「正当な管理者が正しいフローに沿って作成したユーザー」と「外部者が勝手に作成した不正なユーザー」を区別して処理しなければ、正当なユーザー登録フローを迂回してアプリケーションにアクセスされる可能性があります。例えば社内システムにおいて、「社内の誰でも閲覧可」を意図して「ログイン済みなら誰でも閲覧可」とアクセス制御を実装すると、社外の攻撃者は自己サインアップをすることでその情報を閲覧できてしまいます。他には有料会員制サービスにおいて、正当な登録フローを迂回することで、利用料を払わずにサービスを利用できてしまう可能性があります。

対策

ユーザーが「正当な管理者が正しいフローに沿って作成したユーザー」かどうかを表現するには、custom claim が有用です。Custom claim は Firebase Authentication 上のユーザー情報に独自のフィールドを作ることができる機能で、このフィールドはクライアント側から書き換えられないため、アクセス制御に必要な追加情報の格納に適しています。正当なフローに沿って作成したユーザーであることを示す custom claim として例えば createdByAdmin: true を付与する処理を、ユーザー作成フローに加えましょう。ユーザーに custom claim を付与す るには Admin SDK の BaseAuth.setUserClaims メソッド を使用します。

await getAuth().setCustomUserClaims(uid, { createdByAdmin: true })

Firestore, Cloud Storage, Cloud Functions 等全てのバックエンドサービスにおいて、createdByAdmin: true であるようなユーザーだけにアクセスを許可するようにしましょう。例えば Firestore においては、次のようにセキュリティールールを記述しましょう。

function userIsValid(auth) {
  return (
    // 正当な管理者が正しいフローに沿って作成したユーザーでなければならない
    auth.token.createdByAdmin &&
    // ...
    // 他にチェックすべき条件もあるため、以降の解説で条件を追加していきます
  )
}

match /hoge/{hogeID} {
  allow read: if (
    userIsValid(request.auth) &&
    // ...
    // アプリケーションの仕様に沿ってアクセス制御を実装してください
  )
}

なお Google Identity Platform では、自己サインアップを禁止する設定項目が存在します。したがって Firebase Authentication から Google Identity Platform にアップグレードして適切に設定を行うことでも、自己サインアップを防ぐことができます。詳しくは Nil Hiiragi さんのこちらの記事をご参照ください。

不十分な対策

Cloud Functions において、ユーザー登録をトリガーとし当該ユーザーの削除処理を行う関数を作成するという方法が考えられるかもしれません。短時間でユーザーが削除されるため、自己サインアップを悪用した攻撃は比較的困難になりますが、ユーザー登録から削除までタイムラグが存在するため悪用不可能とまでは言えません。「対策」にて紹介した確実な対策をお勧めします。

落とし穴 2. ユーザーが自身を削除できる

自己サインアップと同様の注意点ですが、ユーザーは deleteUser 関数 を用いることで任意の時点で自身を削除できます。

対策

具体的な対策はアプリケーションの仕様次第ですが、ユーザーがいつ自身を削除してもアプリケーションに不具合が生じないよう、仕様設計や実装を行ってください。

落とし穴 3. 他人のメールアドレスを用いたユーザー登録

どのようなアプリケーションであれ、ユーザーに紐付くメールアドレスはそのユーザー自身のものであることが想定されているはずです。ユーザーに紐付くメールアドレスをそのユーザーが本当に所有しているかどうかを確認することを、メールアドレスの疎通確認と呼びます。Firebase Authentication ではユーザーに紐付くメールアドレスに確認用 URL を送信し、ユーザーはその URL を開くことでメールアドレスの所有を証明する、という機能が sendEmailVerification 関数などで提供されています。

Firebase Authentication のメールアドレス / パスワード認証では、メールアドレスの疎通確認をせずともユーザー登録やログインが可能です。つまり、他人のメールアドレスを用いてアプリケーションを利用できてしまいます。あるいはユーザー登録後に、メールアドレス変更機能を用いて他人のメールアドレスに変更することもできます。そして、疎通確認が完了していないユーザーのログインを禁止できるような設定項目はありません。

リスク

リスク 3-1. メールアドレス誤入力によるユーザー乗っ取り

A さんがユーザー登録時に、メールアドレスを誤入力してしまったとします (入力したメールアドレスを john@example.com とします)。そして、 john@example.com はたまたま B さんが所有していたとします。

Firebase Authentication ではメールアドレスの疎通確認をせずともユーザー登録ができるため、A さんはメールアドレスを誤入力したことに気づかないままアプリケーションを利用してしまうかもしれません。ここで B さんは自分のメールアドレス john@example.com に対してパスワードリセットを行うことで、A さんが登録したユーザーとしてログインできます。すると、A さんがアプリケーションに入力した個人情報などを B さんが閲覧できてしまいます。もし A さんが決済情報を登録していたら、B さんは A さんの決済情報を用いて購入操作などをできてしまうかもしれません。

リスク 3-2. 他人にメールを送りつけさせる

もし他人のメールアドレス john@example.com を用いてユーザー登録すると、アプリケーションがユーザーに送るメールは全て john@example.com に届きます。この事象は大した問題ではないように思えるかもしれませんが、アプリケーションのメール送信関連の仕様によっては大きなリスクに繋がることもあります。

例 3-2-1. メール本文にユーザー入力が挿入されるアプリケーション

メール先頭に「(ユーザー名) 様」と記載したり、本文中に申し込み内容を挿入したりと、アプリケーションが送信するメールにユーザー入力が含まれることは珍しくありません。ここでメールに挿入されるユーザー入力の長さや文字種などの制約が不十分だと、攻撃者は実質的にメールの本文を偽装できる場合があります。

例えばアプリケーションがユーザー名の長さや文字種に制約を課していないとします。攻撃者はユーザー名を次のように設定します。

お客様\n以下の URL からログインしてください。\nhttps://phishing.example/signin\n\n\n... (以降大量の改行文字)

アプリケーションが送信するメールに「(ユーザー名) 様」という記載をする場合、ユーザーには次のようなメールが届くことになります。

アプリケーションが本来送信したかった内容は大量の改行によって画面外に押し出されてしまい、攻撃者が仕込んだ文字列だけが表示されてしまうのです。

このようにして、攻撃者は被害者にフィッシングメールを送信できます。ここでメールの差出人は本物のアプリケーションのメールアドレスであるため、通常のフィッシングメールと比べ騙されやすいでしょう。

今回は簡単のため、ユーザー名に改行文字を含められるというアプリケーションの不備3を仮定して説明しました。しかし改行文字が禁止されていても大量の空白文字を挿入したり、改行を使わずに自然なメッセージを埋め込んだりできるかもしれません。また、ユーザー名以外のユーザー入力では改行文字を許容せざるを得ないこともあるでしょう。

メールに自由に文字列を挿入できても疎通確認をきちんと行っていれば、攻撃者が文言を細工してもそのメールは攻撃者の元に届くため攻撃は成立しません。単体では無害な性質が、疎通確認の欠如と組み合わせられることで精巧なフィッシングという重大なリスクに発展しうるのです。

例 3-2-2. プロモーションメールを送るアプリケーション

ユーザーにプロモーションメールを送るアプリケーションでは、攻撃者は被害者のメールアドレスで勝手にユーザー登録することで、被害者に身に覚えのないプロモーションメールを送りつけることができます。これはアプリケーションのレピュテーションリスクに繋がります。

例 3-2-3. メール送信を伴う操作を短時間で大量に実行可能なアプリケーション

申し込み完了メールなど、ユーザーの操作に伴ってユーザーにメールを送信する機能があるとします。この操作を短時間で大量に実行できる場合、攻撃者は他人のメールアドレスでユーザー登録したのちメール送信操作を大量に実行することにより、他人に大量のメールを送りつけさせることができます。これもまたアプリケーションのレピュテーションリスクに繋がります。

リスク 3-3. メールアドレスに基づくアクセス制御の迂回

ユーザーのメールアドレスに基づいてアクセス制御を行っているアプリケーションでは、攻撃者が自分の所有していないメールアドレスを用いてユーザー登録することで、そのアクセス制御を迂回できる可能性があります。

例えば社内システムにおいて自社ドメインのメールアドレス *@company.example.com に紐付くユーザーのみにシステム利用を許可しているとします。社外の攻撃者は john@company.example.com としてユーザー登録することで、社内システムを不正に利用できてしまいます。

学生限定のサービスを提供するアプリケーションにおいて、メールアドレスのドメインが .ac.jp で終わるかどうかをもって学生かどうかを判定するような場合でも、同様の不正利用が考えられるでしょう。

対策

先述した通り、Firebase Authentication において「メールアドレスの疎通確認を行っていないユーザーがログインできないようにする」という設定はできません。

ユーザーのメールアドレス情報を一切利用しないアプリケーションであれば、これまでに例示したリスクは発生しないでしょう。ユーザーのメールアドレスを利用するアプリケーションの場合は、疎通確認が完了していないユーザーがアプリケーションを利用できないようにアクセス制御を実装することが対策となります。

メールアドレスの疎通確認が完了しているかどうかは、Firebase セキュリティールールにおいては request.auth.token.email_verifiedを用いて判定できます。各言語の Firebase SDK, Admin SDK においても、細かなプロパティー名は異なりますが同様の情報が提供されています。Firestore, Cloud Storage, Functions など全てのバックエンドにおいて email_verified プロパティーをチェックすることで、メールアドレスの疎通確認が完了していないユーザーにアプリケーションを利用させないようにできます。先述した自己サインアップの対策と合わせると、セキュリティールールは次のようになります。

function userIsValid(auth) {
  return (
    auth.token.createdByAdmin &&
    // メールアドレスの疎通確認が完了していなければならない
    auth.token.email_verified &&
    // ...
    // 今後もさらに条件を追加していきます
  )
}

OAuth 2.0 プロバイダーを利用している場合でも、email_verified のチェックは必要です。というのも OAuth 2.0 プロバイダーを用いて登録したユーザーであっても、updateEmail 関数を用いてメールアドレスの変更ができるためです。疎通確認はメールアドレス / パスワード認証の場合と同様に、先に紹介した sendEmailVerification 関数を用いて行うことができます。

ところで、「リスク」において紹介した具体的な攻撃の例の中には、メールアドレスの疎通確認不足に加えて「アプリケーションが送信するメールに自由に文字列を挿入可能」「メール送信を伴う操作を短時間で大量に実行可能」という別の不備を利用したものがありました。先述したメールアドレスの疎通確認に関する対策に加えて、これらの不備に対策をしておくことももちろん大切です。

落とし穴 4. メールアドレスに紐付くユーザーが存在するかどうか判定可能

fetchSignInMethodsForEmail 関数は、与えたメールアドレスに紐付く認証プロバイダーの一覧を返します。返り値が非空ならば、そのメールアドレスに紐付くユーザーが存在することがわかります。この関数は未認証状態でも実行できるため、「あるメールアドレスに紐付くユーザーが存在するか調べる」ということが誰にでもできます。

リスク

マッチングアプリなどアプリケーションの内容によっては、利用者であることを他人に知られることがユーザーに不利益をもたらすかもしれません。利用状況を他人に知られても問題がないようなアプリケーションであっても、「アプリケーションの利用者である」という情報が標的型メールなどに悪用されるかもしれません。またブルートフォース攻撃において、アプリケーションで利用されているメールアドレスに絞り込んでからメールアドレスとパスワードの組を総当たりすることで、利用状況の情報がない場合と比べて試行回数を減らすことができます。

対策

メールアドレスと紐付けられない認証プロバイダーのみを利用することが、根本的な対策となります。そのような認証プロバイダーとしては匿名認証や電話番号ログインが挙げられますが、これらのプロバイダーには欠点4もあり、一概に推奨されるものではありません。OAuth 2.0 を利用した認証においてメールアドレスを取得するスコープを要求しないことでも、メールアドレスに紐付けられないユーザーを作成できます。しかし多くの OAuth 2.0 プロバイダーは、Firebase SDK をそのまま利用するとデフォルトでメールアドレスを閲覧できるスコープが要求されるため、これを回避するにはフローを自分で実装する必要があります。このように根本的な対策にはデメリットもあるため、先述したリスクをどこまで許容できるかを考慮して対策を検討することをお勧めします。場合によっては Firebase Authentication 以外の IDaaS を利用することも視野に入れると良いでしょう。

また Identity Toolkit API の割り当てを小さくすることで、fetchSignInMethodsForEmail 関数を繰り返し用いて有効なメールアドレスを収集する行為を妨げることができます。割り当ての引き下げは次節で紹介するリスクの対策を兼ねており、公式ドキュメント「Firebaseのセキュリティチェックリスト」でも推奨されているため、実施することをお勧めします。ただしこの対策は根本的なものではありません。「交際相手のメールアドレスを入力してマッチングアプリを利用しているか調べる」というように、特定のメールアドレスの利用状況を調べる攻撃に対して割り当ての引き下げは無力であることに注意してください。

落とし穴 5. メールアドレス / パスワード認証のブルートフォース

認証機構に対する基本的な攻撃の 1 つであるブルートフォース攻撃ですが、実は Firebase Authentication においてもブルートフォース攻撃の対策が必要です。

攻撃者が一定時間内に実行できるログイン試行の数は、Identity Toolkit API の割り当てによって制限されています。同一の IP アドレスから 1 分間あたりに実行できる Identity Toolkit API の回数は、次のコマンドで確認できます (リファレンス)。

gcloud alpha services quota list \
--service=identitytoolkit.googleapis.com \
--consumer=projects/プロジェクトID \
--flatten='consumerQuotaLimits' \
--filter='metric:"identitytoolkit.googleapis.com/default" AND consumerQuotaLimits.unit:"1/min/{project}/{user}"'

コマンドの出力例は以下の通りです。コマンド出力の effectiveLimit の値が、同一の IP アドレスから 1 分間あたりに実行できる Identity Toolkit API の回数を表します。defaultLimit の値は 2022/03 調査時点で 3 万回であり、ブルートフォース攻撃に対する他の防御機構がないと仮定すると、同一の IP アドレスから 1 分間あたりに 3 万回もログインを試行できる可能性があります。

consumerQuotaLimits:
  metric: identitytoolkit.googleapis.com/default
  quotaBuckets:
  - defaultLimit: '30000'
    effectiveLimit: '30000'
  unit: 1/min/{project}/{user}
displayName: Queries
metric: identitytoolkit.googleapis.com/default

なお、GCP コンソールからも割り当ての値を確認できます。「Queries per minute per user」という行の上限値を参照してください。

GCP コンソールにおける Identity Toolkit API の割り当て確認画面

ブルートフォース攻撃とその対策の必要性はほとんどの開発者が認識していることでしょう。しかし Firebase Authentication においてそれを防ぐための設定は Firebase コンソールから確認できるものではなく、GCP のコンソールや CLI から変更する必要があるため、対策が漏れているアプリケーションは多いのではないでしょうか。

対策

メールアドレス / パスワード認証を利用しないことが根本的な対策となります。公式ドキュメント「Firebase のセキュリティチェックリスト」では OAuth 2.0 プロバイダーがもっとも安全な認証プロバイダーであるとして推奨されています。

どうしてもメールアドレス / パスワード認証を利用する必要がある場合は、根本的な対策とはなりませんが、ブルートフォース攻撃を緩和する次のような対策をお勧めします。

まず Identity Toolkit API の割り当てを小さくすることで、攻撃者が一定時間内に実行できるログイン試行の数を減らすことができます。このことは、公式ドキュメント「Firebase のセキュリティチェックリスト」でも推奨されています。ただし Identity Toolkit API の割り当てはログインだけでなく、ユーザー登録やパスワードリセットなど Firebase Authentication の他の機能と合算した回数に対する制限であるため、割り当てを過度に小さくするとアプリケーションの正常な利用に支障を来す可能性があります。アプリケーションの通常の使用方法における Identity Toolkit API の利用状況の測定や割り当て超過エラーの検知を行い、適切な割り当てを検討すると良いでしょう。

またパスワードの構成要件を堅牢にすることで、ブルートフォース攻撃を成功させにくくすることも緩和策となります。パスワードの構成要件については、次節で詳しく扱います。

ちなみに認証機構を自作する場合のブルートフォース攻撃対策については、以下のブログで解説しています。

落とし穴 6. パスワードの脆弱な構成要件

メールアドレス / パスワード認証を利用する場合、ユーザーが容易に推測可能なパスワードを設定できないようにして、乗っ取りを防ぐことが重要です。Firebase Authentication では 6 文字未満のパスワードを設定しようとするとパスワードが弱すぎる旨のエラーが発生します (ドキュメント) が、6 文字以上であれば aaaaaa のような単純なパスワードであっても設定できてしまいます。

対策

堅牢なパスワード構成要件を設計し、アプリケーションにおいてパスワードを設定する全ての箇所で、設定しようとするパスワードが構成要件を満たすかどうかの検証を実装してください。構成要件を設計するうえでは、NIST SP 800-63B 5.1.1OWASP ASVS V2.1 などのガイドラインが参考になります。

この対策は一般的な Web アプリケーションにおいて行われるべき措置であり、Firebase Authentication 特有の事項があるわけではありません。本節でお伝えしたいことは、「IDaaS を使っていればセキュリティーは大丈夫」などと盲目的に信用せず、どのようなリスクが対策済みなのかを把握し、残されたリスクに適切に対策を施すべきであるということです。

落とし穴 7. 異なる目的で有効化された認証プロバイダーの区別

本節の内容は気をつけるべき Firebase Authentication の仕様というよりは、開発者の不注意によって生まれやすい脆弱性です。

Firebase Authentication ではメール認証や Google ログインなど、複数の認証プロバイダーを併用できます。アプリケーションによっては、複数の認証プロバイダーを異なる目的で利用している場合があるでしょう。このようなアプリケーションではアクセス制御の際に「ユーザーがどの認証プロバイダーを利用しているか」を適切に検証しなければなりません。

このことは言葉にすると当たり前に聞こえますが、この点に注意せず認証プロバイダーを新たに有効化すると、アプリケーションに不具合が生じる可能性があります。例えば Google ログインだけを認証に用いているアプリケーションを考えます。ある日キャンペーンとしてアプリケーションにミニゲーム機能を追加することになり、アプリケーションに本登録しなくてもハイスコア情報を記録できるよう匿名認証を有効化したとします。このときもしアプリケーション本体が Google ログイン以外の認証プロバイダーを想定していない場合、匿名認証のユーザーを本登録ユーザーと同等に扱ってしまい、予期しない挙動に繋がる可能性があります。

対策

複数の認証プロバイダーを異なる目的で使い分けている場合は、アクセス制御において認証プロバイダーが仕様に沿ったものであるかどうかをホワイトリスト方式で検証しましょう。

現在単一の認証プロバイダーしか有効化していない場合は、現時点で「想定外の認証プロバイダーの利用」という事象は起き得ませんが、先述した例のように将来的な変更によって問題が生じる可能性はあります。認証プロバイダーを 1 つしか有効化していない場合であっても、予防的な対策として認証プロバイダーをホワイトリスト方式で検証することをお勧めします。

自己サインアップメールアドレスの疎通確認チェックの対策と合わせると、Firestore セキュリティールールは次のようになります。例として、メールアドレス / パスワード認証と Google ログインだけを想定しているとします。

function userIsValid(auth) {
  return (
    auth.token.createdByAdmin &&
    auth.token.email_verified &&
    // 認証プロバイダーをホワイトリスト方式で検証
    auth.token.firebase.sign_in_provider in ['password', 'google.com'] &&
    // ...
    // 本稿で推奨するチェックは以上です。
    // アプリケーションの仕様上他に必要なチェックがあれば追加してください。
  )
}

また認証プロバイダーの有効化や設定変更を行う際には、アプリケーションのあらゆる箇所に対してその変更が及ぼす影響を考えてから変更を実施することをお勧めします。

ベストプラクティス

Firebase Authentication をはじめとする様々な Firebase プロダクトを利用するうえでのベストプラクティスは、以下の資料などにまとめられています。本稿と重複する内容も含まれますが、是非ご参照ください。

おわりに

本稿では IDaaS の 1 つである Firebase Authentication について、アプリケーションによっては不具合や脆弱性のもととなる仕様とその対策をご紹介しました。

この記事の主旨は決して「Firebase Authentication は危険だから使うべきでない」ということではありません。どのような IDaaS であれ、IDaaS の仕様と自分のアプリケーションの仕様を考慮して、IDaaS や認証プロバイダーを選定し適切な設定を行いましょう。IDaaS とアプリケーションの仕様のミスマッチにより不具合が生じうる場合は、その対策を実装しましょう。

Firebase は簡単にアプリケーションを構築できる便利な mBaaS ですが、完成を急ぐあまりセキュリティー対策を疎かにしてしまうと、どれほど素晴らしいサービス内容であってもいつの日か脆弱性攻撃によって大きな被害を受ける可能性があります。Firebase を用いて開発をされている皆様が、自らのアプリケーションを脅威から守り、ユーザーに素晴らしいサービスを届けていくことに、本記事を一助としていただければ幸いです。

Flatt Security Blog では、これまでも Firebase をセキュアに利用するための情報を発信しております。Firestore セキュリティールールの実装など、Firebase Authentication 以外のプロダクトについても解説しておりますので、Firebase ユーザーの方はぜひこちらもご一読ください。

また、Flatt Security が提供するセキュリティ診断サービスでは、Firebase をセキュアに扱えているか専門家の視点でチェックする Firebase 診断というメニューも提供しています。

これまでの経験から正直に申し上げますと、Firebase を利用したアプリケーションには攻撃されるとサービスの継続が困難になるような深刻な脆弱性が見つかるケースが多いです。専門的な診断を行ったことがない場合は、ぜひ利用をお勧めします。

ご興味のある方向けに下記バナーよりセキュリティ診断の料金に関する資料もダウンロード可能です。Web アプリケーションの診断にどの程度費用が発生するかを、ご自身で計算できるようになっています。

Firebase 診断だけはどうしても個別のお見積りが必要ですので、ご自身での料金計算はできないのですが、Firebase Authentication, Firestore, Cloud Functions それぞれに対する診断の具体的な料金例も掲載されておりますので、参考にしていただけるかと思います。

また、Flatt Security はセキュリティーに関する様々な発信を行っています。最新情報を見逃さないよう、公式 Twitter のフォローをぜひお願いします!

twitter.com

ここまでお読みいただきありがとうございました。

更新履歴

2022 年 4 月 21 日 「自己サインアップ」の対策において、Firebase Authentication から Google Identity Platform にアップグレードする方法を追記しました。この方法を発信してくださった Nil Hiiragi さんにこの場を借りて御礼申し上げます。

2022 年 5 月 2 日 「メールアドレス / パスワード認証のブルートフォース」において、可能なログイン試行の回数について断定的と解釈できてしまう表現を修正しました。

2022 年 6 月 30 日 「createUserWithEmailAndPassword 関数」と書くべきところを誤って「signInWithEmailAndPassword 関数」と記載していた箇所を修正しました。


  1. 本稿で Firebase Authentication の API について述べる際は特記なき場合 JavaScript SDK (version 9) を例に説明します。ただしほとんどの議論は SDK の言語やプラットフォームの種別 (Web, iOS, Android 等) によらず同様です。

  2. Firebase Authentication のドキュメント等において、この行為を指す用語は特にないようです。同様の行為が Cognito において「自己サインアップ」と呼ばれていることから、本稿ではこの語を Firebase Authentication に流用しています。

  3. ちなみに、Firebase Authentication においてユーザーの displayName には改行文字を含めることができます。

  4. 匿名認証はデバイスを喪失した場合に再ログインができないなどのデメリットがあることから、利用者が本登録するまでの一時的な利用にとどめることが推奨されています (ドキュメント)。電話番号ログインについては、機種変更などでユーザーが電話番号を手放し、他人がその電話番号を取得することで乗っ取りが発生しうるなどのリスクが指摘されています (ドキュメント)。