かもメモ

自分の落ちた落とし穴に何度も落ちる人のメモ帳

[WIP] Firebase Cloud Firestore 接続情報が漏れるとパケ死しないか気になっていたので調べてるメモ

最近Compass漁ってNuxt+Firebase とかReactNative(Expo)+FirebaseとかのHands-onに色々と参加していました。

フレームワークで生成した静的ファイル(HTML+CSS+JavaScript)をFirebaseやNetlifyにデプロイすれば簡単にFirebaseと連動したWEBサービス・アプリがが作れてマジヤバイ (語彙力 という感じです。

しかしながら僕のような古(いにしえ)のほうむぺぃじ作ってきたマンとしては、firebaseとか従量課金だと設定漏れて悪用されたらパケ死しない???という不安もあり、生成されたものがブラックボックスなままでは

  • 静的ファイルならどうやってFirebaseと接続してるの?
  • 接続に必要な設定ファイルはどういう扱いになっているんだろう?
  • JavaScriptで読み込むとローカル側に設定ファイルDLするよね?

というような疑問が残ったままになっていました。

Nuxt generate で生成された静的ファイルの中身

Nuxtが吐き出した静的ファイルのディレクトdist内でagコマンド(The Silver Searcher)を使ってfirebase apiKeyを検索。
-lオプションを付けるとマッチしたファイル名だけ返してくれます。

$ cd dist
$ ag -l <firebase apiKey>
_nuxt/cf55170e35703f7a131c.js

nuxt generateで生成されたJavaScriptファイルに.envに書いてたFirebaseの接続情報がバンドルされているようです。

firebase serve コマンドを実行すると、Firebaseのdeploy先に指定していたディレクトリをルートにしたローカルサーバーで確認ができるようです。
これで先程のfirebase apiKeyが含まれているファイルが使用されているか見てみます。

$ firebase serve
i  hosting: Serving hosting files from: dist
✔  hosting: Local server: http://localhost:5000

ブラウザhttp://localhost:5000にアクセスして、devtoolを開いて確認します。
f:id:kikiki-kiki:20190122075825p:plain
読み込まれていました。

やはり静的化されたものでは直接設定ファイルを読み込んでFirebaseにアクセスしているようです。

Firebase Hosting だと接続情報はそもそも見ることが出来る

Firebase Hostingを使っているとhttps://{Hosting Domain}/__/firebase/init.jsonで接続情報が見れるみたいです。

Firebase Hosting は、/__ で始まるサイトの URL を予約します。この予約された名前空間により、Firebase Hosting と他の Firebase 機能を簡単に同時利用できます。予約済みの URL は、デプロイ時だけでなく、firebase serve をローカルで実行したときにも利用されます。
SDK の自動構成
SDK 自体をホスティングするだけでなく、予約済みの名前空間では、Firebase Hosting サイトに関連するプロジェクトの SDK の初期化に必要な構成も提供されます。これは、直接追加できるスクリプトとして提供されます。

<!-- load Firebase SDK before loading this file -->
<script src="/__/firebase/init.js"></script>

出典: 予約された URL  |  Firebase

アプリケーション側からCloud Firestoreに新しいコレクションを作成することが出来るのか?

接続情報は誰でも見れる状態なので、テストモードの誰でも読み書きできるデータベース設定・ドメインホワイトリストを設定していない状態で、アプリケーション側からCloud Firestoreに新しいコレクションを作成できるのか調べてみました。

https://{Hosting Domain}/__/firebase/init.jsonで取得できた接続情報を元に次のような存在しないコレクションevil-tableにデータを追加しようとするスクリプトのあるHTMLを作成しました。


<html>
<body>
<script src="https://www.gstatic.com/firebasejs/5.8.0/firebase.js"></script>
<script src="https://www.gstatic.com/firebasejs/4.12.1/firebase-firestore.js"></script>
<script>
// Initialize Firebase
var config = {
  apiKey: "<init.jsonにあるapiKey>",
  databaseURL: "<init.jsonにあるdatabaseURL>",
  storageBucket: "<init.jsonにあるstorageBucket>",
  authDomain: "<init.jsonにあるauthDomain>",
  messagingSenderId: "<init.jsonにあるmessagingSenderId>",
  projectId: "<init.jsonにあるprojectId>"
};
firebase.initializeApp(config);

const db = firebase.firestore();
// 存在しないコレクションにデータを追加してみる
db.collection("evil-table").add({
  name: 'new item'
})
.then((res) => console.log("Document written with ID: ", res.id))
.catch((err) => console.error("Error adding document: ", err))
</script>
</body>
</html>

これを適当なドメインを割り当てているサーバにおいてアクセスしてみます。
コンソールをみてみると...

> Document written with ID:  QHHn09EqgvNvZxSifBdU

データ作れてるっぽい。
FirebaseコンソールにアクセスしてDatabaseの項目を見てみます。
f:id:kikiki-kiki:20190122130932p:plain
データ作られちゃってますね... (゚∀゚)アヒャャャャャャ

だでれも読み書きできるテストモードのままだと、誰でも新しいDBのテーブルが作れるちゃうので他人のFirebaseアカウントに寄生したアプリとか作れちゃうのでは🤔

Firebase の接続情報より権限設定の方が重要っぽい

Firebase リリース チェックリスト
WEB: 不正使用を防ぐためのドメインホワイトリストを追加します。 - Google Developer Console のブラウザ API キーとクライアント ID の運用環境ドメインホワイトリストに登録 - Firebase コンソール パネルの [Auth] タブにある運用環境ドメインホワイトリストに登録
Cloud Firestore
意図しないデータアクセスを防ぐためにセキュリティ ルールを構成します。
出典: Firebase Launch Checklist  |  Firebase

cf.

The apiKey essentially just identifies your Firebase project on the Google servers. It is not a security risk for someone to know it. In fact, it is necessary for them to know it, in order for them to interact with your Firebase project.
In that sense it is very similar to the database URL that Firebase has historically been used to identify the back-end: https://<app-id>.firebaseio.com. See this question on why this is not a security risk: How to restrict Firebase data modification?, including the use of Firebase's server side security rules to ensure only authorized users can access the backend services.
出典: javascript - Is it safe to expose Firebase apiKey to the public? - Stack Overflow

まとめ

Hands-onで静的ファイルの場合は設定ファイルをサーバーに上げて直接アクセスはできなくする。FirebaseにHostingする場合はFirebase側に設定があるから不要。Nuxtの場合はプロジェクト生成時に.envdist/*が自動的に.gitignoreされるのでFirebaseの設定ファイルがGitHubに上がったりすることはないので安心と聞いていたのですが、そもそもFirebaseの設定は見れても問題がなくて、むしろCloud Firestoreのルール設定や不正使用を防ぐためのドメインホワイトリストの設定の方が重要な印象を受けました。接続情報のモーダルがそもそも、scriptタグに囲まれたのをHTMLに貼り付けてくださいって出てきてますものね...

なのでHands-onなどでDatabaseはテストモードのままサクッと作ったアプリを雑に公開していていたり、接続情報が入ったファイルをGitHubにpushしていたりして、悪意のある誰かに見つかってしまうと接続情報からDBに寄生したアプリに利用されたり、遊び半分に大量のデータを投稿するボット作られちゃったりで、パケ死する可能性がなくもないのでは?と感じました。

サクッとアプリが作れるのはすごいのですが、Cloud Firestoreのルール設定やFirebaseの請求のアラート設定などは、公開をゴールにするHands-onならしっかり説明しておいて欲しいなって思いました。
Firebaseセキュリティ設定のHands-onぜひ開催してください!!


[参考]

firebaseの設定関連の参考サイト

WEB+DB PRESS Vol.105

WEB+DB PRESS Vol.105

  • 作者: 小笠原みつき,西村公宏,柳佳音,志甫侑紀,池田友洋,木村涼平,?橋優介,大塚雅和,飯塚直,吉川竜太,末永恭正,久保田祐史,浜田真成,穴井宏幸,大島一将,桑原仁雄,牧大輔,池田拓司,はまちや2,竹原,WEB+DB PRESS編集部
  • 出版社/メーカー: 技術評論社
  • 発売日: 2018/06/23
  • メディア: 単行本
  • この商品を含むブログを見る

実践Expo React NativeとFirebaseで、SNSアプリを最速ストアリリース! (NextPublishing)

実践Expo React NativeとFirebaseで、SNSアプリを最速ストアリリース! (NextPublishing)