👏

「Firebase Authentication 7つの落とし穴」のリスクを再整理する

2022/04/27に公開5

https://twitter.com/kuwahara_jsri のやってる朝活Twitterスペースで以下の記事を知りました。

https://blog.flatt.tech/entry/firebase_authentication_security

もちろんこういったリスクを列挙、検討するのは重要なことなのですが、

  • Firebase Authentication関係ない話では
  • あれ、仕様に関して勘違いしてる?

というのがいくつかあったので、再整理していきます。リスクは列挙することには業務上あまり意味はなく、評価され、リスクを受け入れるか外すかを判断するところが重要なので。

IDaaSは脆弱性を生み出すか

IDaaS を導入することにより、逆に脆弱性が生まれることもあります。(中略) Firebase Authentication は他の IDaaS と比べて設定項目が少ないという特徴があります。

もちろんここに書かれてることは間違いではありません。ただ、少し実装にフォーカスが寄りすぎていると思っています。セキュリティを考える上では、まずISO27018をはじめとした主要なセキュリティ規格やプライバシー規格を俯瞰する必要があります。

Firebase のプライバシーとセキュリティ

「IDaaSを導入しないと判断するならこれを自己取得してますよね?」までは大上段すぎる話ですが、実装という小さな話の前に「個人情報の管理体制」(ベネッセ大規模情報流出事件を彷彿させますね)、次に管理サーバまわりのセキュリティという話がくると思ってて、そう思うとIDaaS 導入で脆弱性が生まれることはゼロではありませんが、一方でもっと(実装コード以外の)メリットに光があてられるべきだと感じました。

自己サインアップ

ここにあるリスクはまさにその通りです。 私がつくってる社内システムでは、ドメインと email_verified (メールアドレス認証済み)のふたつをもってみたり、事前に登録のあるメールアドレスのみ許可したりしていますが、記事にあるように

「サインアップ画面を用意していないからユーザは新規登録できない」

というのは脆弱性となるので対策すべきです。

Firebase において API キーは機密情報ではありません

これは少し誤解を招きかねないので補足しておきますが、正しくは「Firebaseは、(Publicな)API Keyと管理用の秘密鍵が別に用意されております」が正しい表現です。本文にあるように「自己サインアップ等」は可能ですが、他者のアカウント操作などは行うことはできません。

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

これはそのとおりですね。自己サインアップ同様、「Public API Keyを使ってエンドポイント直たたきでユーザが削除されてしまうことによってアプリケーション上で不整合が生まれてしまうかもしれない」というリスク自体は存在します。

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

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

「メールアドレス誤入力によるユーザー乗っ取り」は「IDaaSによる脆弱性」ではなく、Emailの所有確認をいれなかった仕様の問題です。そういう意味では、「IDaaSだから、Firebase Authenticationだから」という固有の問題と、ただの仕様策定ミスであって、IDaaSでなくても起こりうる問題は切り離して考えるべきでしょう。

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

「大量スパムが(Firebase Authentication経由で)送れてしまう」ことについては、Firebase Authenticationは「申し込みによる割り当ての管理」を実装しています。

プロジェクトを不正行為から守るため、同じ IP アドレスでアプリケーションが使用できる新しいメールとパスワード、匿名での申し込みの数を制限しています。ここで、この割り当てを一時的に変更するようリクエストしたり、スケジュール設定したりできます。

なので、新規登録/匿名についてはここでコントロールすべき事項でしょう。パスワードのリセットについては懸念のことは実現してしまいますが、(パスワードリセットのURLが送られてきて、そのURLをクリックしたユーザ自体が新パスワードを設定するので)そういう攻撃をしても意味がないんですよね・・・。あと後述しますが、Firebaseとしては不正利用は別途の対策も行っていると述べています。

アプリケーションがユーザー名の長さや文字種に制約を課していないとします。

以下がFirebaseの定型文なのですが、本記事でふれているのは %DISPLAY_NAME% の部分です。

件名
%APP_NAME% のログイン用メールアドレスが変更されました
メッセージ
%DISPLAY_NAME% 様

ドキュメントにある以下のところですね。

重要: displayName や photoURL など、ユーザーに表示される可能性がある UI の値を設定(および後で表示)する際は注意が必要です。API は、潜在的な XSS タイプの攻撃を防ぐための値のフィルタリングを行いません。

https://firebase.google.com/docs/auth/web/manage-users?hl=ja&authuser=0

なのですが、検証してみました。

updateProfile(user, {
  displayName: '\n以下の URL からログインしてください。\nhttps://phishing.example/signin\n\n\n'
})

でdisplayNameを変更したのですが、実際にきたメールは以下の通りです(メアドは変更しています)

以下の URL からログインしてください。 様

project-457600014723 のログイン用メールアドレスが info@example.com に変更されました。

メールの変更を依頼していない場合は、次のリンクをクリックして、ログイン用メールアドレスをリセットしてください。

改行記号とURLが削除されていますね。これではフィッシングメールは送信することができません。
私が検証した中ではこの通りでしたが、本当にこの攻撃は成功しましたでしょうか??

攻撃者は被害者にフィッシングメールを送信できます。

できませんでした。

疎通確認の欠如と組み合わせられることで精巧なフィッシングという重大なリスクに発展しうるのです。

できませんでした。

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

所有確認をしてください(所有確認をせずにプロモーションメールを送ること自体が問題です。あとFirebase Authenticationは関係ありません)

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

所有確認をしてください。

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

所有確認をしてください。

「メールアドレスの疎通確認を行っていないユーザーがログインできないようにする」

これ仕様として説明しておきますが、まずFirebaseは新規登録したユーザに対して、tokenを発行します。ただその段階ではユーザの認証確認をしても

auth.token.email_verified: false

となるので「tokenを得てる状態をログインと見なす」仕様で実装しない限り、ログインできていません。バックエンドと連携してる場合でも email_verified は常に確認できます。本記事でも

Firestore, Cloud Storage, Functions など全てのバックエンドにおいて email_verified プロパティーをチェックすることで、メールアドレスの疎通確認が完了していないユーザーにアプリケーションを利用させないようにできます。

と書いてありますが、仕様で決まっていれば当たり前のことというか、漏れて問題が生まれるのはどの実装でも同じなので、これをもってFirebase Authenticationのリスクといってしまうのは個人的に違和感を感じます。

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

利用者であることを他人に知られることがユーザーに不利益をもたらすかもしれません。

これはまさにその通りですね。落とし穴の1と2と同様で、Firebase Authenticationの通信ログを調べたら判明しますので、これはFirebase Authentication自体の問題です。

ブルートフォース攻撃において、アプリケーションで利用されているメールアドレスに絞り込んでからメールアドレスとパスワードの組を総当たりすることで、利用状況の情報がない場合と比べて試行回数を減らすことができます。

これについてはちょっと言及しづらいんですよね。まず、Firebase Authenticationは不正利用について以下のように言及しています。

Firebase Authentication は、エンドユーザーの認証とエンドユーザーのアカウント管理に個人データを使用します。
また、セキュリティを強化し、サインアップや認証時の不正行為を防ぐために、ユーザー エージェント文字列と IP アドレスを使用します

なので、ここから悪意あるブルートフォース攻撃をすべて受け入れる仕様だとは読み取れないんですよね。

stackOverflowで次のような記事がありました:
https://stackoverflow.com/questions/50134344/firebase-auth-brute-force-attack-prevention

The Firebase Authentication service is monitored for abuse. Information about this monitoring and the actions taken on detected abuse is seldom documented though, since the information changes regularly and would be more helpful to abusers than to most developers.

If you think your use-case is being affected by this monitoring or the actions taken upon it, reach out to Firebase support with clear details (i.e. code)on what you're trying to do, and what behavior you seeing.

Google翻訳: 
Firebase認証サービスは不正使用がないか監視されます。ただし、この監視と検出された不正使用に対して実行されたアクションに関する情報が文書化されることはめったにありません。情報は定期的に変更され、ほとんどの開発者よりも悪用者にとって役立つためです。

ユースケースがこのモニタリングまたはそれに対して実行されるアクションの影響を受けていると思われる場合は、Firebaseサポートに連絡して、何をしようとしているのか、どのような動作が見られるのかを明確に説明してください(コードなど)。

これ以上私に言及できるソースはありませんが、記事内にあるような「同一の IP アドレスから 1 分間あたりに 3 万回ものログイン試行が許可されてしまいます」という表現についてどこまで正しさを検証しているのか疑問です(Firebaseに問い合わせて、これについて同一IPの場合は不審なIPでもすべて開放して3万回まで許容されているという返答を得てるようでしたら申し訳ありません)

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

6 文字以上であれば aaaaaa のような単純なパスワードであっても設定できてしまいます。

もちろん「フロントエンド時点で独自バリデーションを実装すべき」は当たり前の話なのですが、落とし穴1, 2と同様にPublic API Keyを確認してcurlで勝手に実行して弱いパスワードで設定できてしまうということ自体は事実です。そこまでして弱いパスワードを設定するユーザを制限というか、リスクとして呼ぶのかは疑問ですが・・・。

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

記事にあるとおりですね。

まとめ

こうやってみると、本来的なFirebase Authenticationで仕様上問題になりうるのは、

  • Public API Keyとcurlでクライアントの操作ができてしまう

という一点ですね。

  • 自己サインアップ
  • ユーザーが自身を削除
  • ユーザの実在確認
  • (脆弱なパスワードを設定されてしまう?)

あたりが該当するでしょうか。ただ一点だけ確認しておきたいのはこれらはどれもPublic API Keyと紐ついた話なので、この問題が致命的であるプロダクトの場合は、フロントエンドでFirebase Authenticationをさわるのではなく、自己管理のバックエンドサーバを経由してFirebase Authenticationをさわる必要がでてくるでしょう。

ただ現代においては、個人情報保護法や(海外展開するなら)GDPRを考えながら、認証まわりを実装するのは難易度がとても大きいので、個人的には容易にIDaaSを採用する風潮になってほしいなと思っています。

それではまた。

Discussion

toyojunitoyojuni

初めまして。Flatt Securityの豊田と申します。(言及いただいた記事の筆者ではございませんが、ブログ記事の内容は自分が管理しています。)

この度は弊社ブログ記事を読んでいただきありがとうございました。

当該記事はもとよりFirebase Authentication固有のリスクだけを論じているのではなく、「使用時にユーザーがミスを犯してしまいそうなポイント」をテーマに記事を執筆しましたので、認識の差があるかもしれませんがご理解いただけますと幸いです。また、本文中に記載の通りIDaaSの利用を否定するものでもございません。

事象をどう捉えるかのスタンスの話は議論しても仕方ありませんので、

私が検証した中ではこの通りでしたが、本当にこの攻撃は成功しましたでしょうか??
できませんでした。

と言及されている点に関してお返事しますと、

メールに関してはFirebaseの機能を使ってメールを送信するケースを想定してはおりません。Firebase Authenticationからユーザーのメールアドレスを取得した上で、メール本文を生成する処理やメールを送信する処理は自前で実装したり、他のSaaSを用いたりする場合を想定しておりました。

また、ブルートフォース攻撃の部分に関しまして、

確かにドキュメントに記載されていない防御機構によって実際にはブルートフォース攻撃が成立しない、という可能性は否定できません。しかし Firebase Authentication を安全に使ってほしいという立場からは、そのような存在が不明瞭な防御機構の存在に頼るのではなく、ドキュメントに記載された防御機構だけが存在していたとしても問題がないように Firebase Authentication を使っていただきたいと考えております。

元記事で意図していたのは「毎分3万回のリクエストが許可される可能性が否定できない」ということでした。ですが「毎分3万回のリクエストが本当に可能である」と誤解を与える文章であったことについては不適切だったと思いますので、改めて表現を検討させていただきます。貴重な情報ありがとうございます!

榊原昌彦榊原昌彦

コメントありがとうございます。

「使用時にユーザーがミスを犯してしまいそうなポイント」をテーマに記事を執筆

私個人としては

このため IDaaS の仕様や設定値次第では、アプリケーションの仕様に適さない操作をユーザーが勝手に実行できる場合があります。
自作した認証機構や他の IDaaS であれば自分のアプリケーションの仕様に合わせてカスタマイズできるのに、Firebase Authentication では自分のアプリケーションをよく知らない Firebase 側が勝手に決めた設定値で固定されていると解釈できます。

という表現が大変気になりました。記事前段での部分なのでご指摘の通りどう捉えるかのスタンスの話ではありますが、セキュリティエンジニアの方のご執筆ということなので、「仕様や設定値」とここで原因を特定してるなら、Firebase固有の仕様の部分、プロダクトでそれを利用する仕様の部分を分けて論じるべきだろうというのが執筆の理由でした。

メール本文を生成する処理やメールを送信する処理は自前で実装したり、他のSaaSを用いたりする場合を想定しておりました。

まさにこの部分はそのひとつで、どちらでも解釈できるのは適切な表現ではなく、またFirebaseはドキュメントにおいて注意書きで「潜在的な XSS タイプの攻撃を防ぐための値のフィルタリングを行いません。」と明記しているので、「自前実装をする時にありうる失敗事例」として区分すべきかと思います。(こういう記事は詳しくない、もしくは未利用者も読みますので)

とはいえもともとの記事の意図である「IDaaS時でも開発者はプロダクト全体を通してセキュアな実装が必要である」というのはまさにそのとおりで、本記事やこのやりとりを通じてひとりでもそれに共感いただける方が増えればいいなという思いは私も同様です。

きっかけとなる記事の執筆・公開ありがとうございました。

toyojunitoyojuni

お返事ありがとうございます!今回ご指摘いただいた点に関して、誤解を招きそうな部分は適宜修正を検討しようと思います。

改めて、丁寧に読んでいただき感謝しております。ありがとうございました。

safu9safu9

これ以上私に言及できるソースはありませんが、記事内にあるような「同一の IP アドレスから 1 分間あたりに 3 万回ものログイン試行が許可されてしまいます」という表現についてどこまで正しさを検証しているのか疑問です(Firebaseに問い合わせて、これについて同一IPの場合は不審なIPでもすべて開放して3万回まで許容されているという返答を得てるようでしたら申し訳ありません)

参考までにこれについては、現時点で実際に同一アカウントに対し5回ほど連続でログインに失敗すると、 auth/too-many-requests エラーが返ってきて少しの間ログインが弾かれます。
参考 : https://qiita.com/marchin_1989/items/ade93705dbf3c72e1ce0

榊原昌彦榊原昌彦

ありがとうございます。すっかり失念していましたが、そういうものもありましたね。
そう思うと「同一アカウント」で考えるとちょっと総当りは難しそうですよね。