2024.10.21
お互い疑心暗鬼になりがちな、経営企画と事業部の壁 組織に「分断」が生まれる要因と打開策
Firestoreのセキュリティルールについて(全1記事)
リンクをコピー
記事をブックマーク
コキチーズ氏(以下、コキチーズ):今日はセキュリティルールについて話そうかなと思います。
自己紹介をこのスライドにもはさんでいます。
先ほどと少し内容が違いますが、GCPやFirebaseも好きで、あとはゲームが好きで、そういうことを書いてます。もう一度言いますけど、コキチーズです。TwitterやGitHubのアカウントはk2wankoで、SlackのIDもk2wankoなので、僕に連絡を取りたかったら、k2wankoでメンションしてくれたら、だいたい届きます。
最近、「めっちゃFirebaseが盛り上がってますね」と、Twitterやいろんなニュースを見て思っていて。「合計1億件以上の個人情報がFirebaseの脆弱性によって公開状態に」というGIGAZINEの記事がありました。
どういう記事かというと、セキュリティ会社の調査によって、Firebase利用企業の62パーセントが、データベースのセキュリティルールに問題があり、機密情報などが公開されていた(というもの)。この機密情報が、記事を読むかぎり、ユーザーのトークンやメールアドレスが含まれている状態だったそうです。
これは、セキュリティルールのミスなので……。セキュリティルールというのは、開発者が設定しなきゃいけないものなんですよね。この記事は、Firebase(の脆弱性)という書き方ですけど、ディベロッパーが正しく設定できていなかったというところがあります。
どういう状態のセキュリティルールだったのか、詳細はわからないです。ですが、おそらくこういう感じです。
.read、.writeがtrue、trueみたいな感じになっていて、全公開のようになっていたか、authで認証してるかどうかだけをチェックみたいな状態になっていたか、ということが想像できるわけですね。
これを踏まえて、「最強のセキュリティルールとは何か?」みたいなことを考えると、何もしない、falseにしておくと最強である、ということがわかります。
(会場笑)
つまり、クライアントで書き込みも読み出しもしなければ安全である、ということになるんです。これで完結するんですけど、そういうわけにはいかないので、ちゃんとやります。
「そもそも、セキュリティルールとは何か?」ということで、Firebaseでセキュリティルールが設定できるサービスは3つあります。
最初のRealtime Database、ちょっと前に追加されたCloud Storage、最近出てきたCloud Firestoreの3つがセキュリティルールを書けるサービスになっています。
Realtime Databaseのセキュリティルールは、たぶん、一番「よくわからん」みたいなものになっています。
そもそもRealtime Databaseとは何かという話を軽くします。
書き込んだ内容をリアルタイムに同期してくれるデータベースで、オフライン時でも書き込めるというのがいいです。あと、クライアントが直接データベースに書き込めるという良さもある。主に、ゲームやチャットを作成するのに向いているサービスということになっています。以降、Realtime DBと呼びます。
Realtime DBのルールは、JSONで書いていくのが基本です。
さっき見せたこんな感じのJSONで、この.read.writeというのが読み出しや書き込みです。この値が“true”になっている時、読み出しや書き込みができます。
条件式を値のところに書くことで、このユーザーは書き込みできて、このユーザーは書き込みできないといったことを、JSONで1つ1つ書けます。
カスケード形式といって、JSONの浅いネスト、上位層のほうで、".read": trueという状態に設定されていると、例えば下の階層のほうで".read": falseとしていても、下の設定は意味がないんです。このルールの意味を見出そうとすると、(この場合)k2wankoには何もアクセスさせたくないという書き方をしたいんだと思います。でも、こういう書き方をしても、それは意味がなくなります。
あと、$otherというものがあります。
これは.writeに書き込み権限があるという状態にしているんだけど、書き込みさせたいデータを制限したい時……例えば好き勝手なプロパティを追加させたりしたくない時は、.validateというものが存在するので、それを使うことができます。
あと、リスト形式のものを取得する時に何件取得するとか、クエリの制限もできます。例えば1万件取られると、それだけパフォーマンスが悪くなってしまうので、取得できるアイテムの数を制限したい場合は、こういう感じでセキュリティルールを書けば制限できます。
けっこういろいろ柔軟にできて、がんばれば大丈夫です。
ただ、JSONで書くのは正直つらいというところもあります。そのつらいポイントとして、JSONはコメントが書けない、関数を定義できないというのが、いろいろあります。
あと、型がないとか、条件分岐とか、ハイライトがつかないとか、つらいポイントがいっぱいあるんですけど、そういうのを解消するために、FirebaseにはBoltというツールがあります。
これは何かというと、コンパイルするとRealtime DB上のセキュリティルールを書き出してくれる独自の言語です。
コメントを書けて、関数を定義できます。TypeScriptのような感じで型の定義もできるので、type user 〇〇と書いた後、このタイプはnameを持っていて、emailを持っていて、という設定もできます。
説明すると大変なんです。path /〇〇という感じで、パスのキーワードをもとに、ここでどういう処理をするかといったことを、プログラムアプリに 0:06:51記述することができます。コメントもできるし、ファンクションも定義できるし、かなり便利です。
あと、書き込み権限をcreate、update、deleteなどで分割して定義することもできます。これはセキュリティルール本来のものでも書けるんだけど、書くのがちょっと冗長になるところをスマートに書けるなど、いろいろと気遣いがあります。けっこう便利なので、Realtime DBを使う時はBoltを使うと、見通しのいいセキュリティルールが書けるようになると思うので、見てみたほうがいいと思います。
でも、これは万能というわけではありません。コンパイルした後のセキュリティルールは、生のJSONをある程度追って、自分の意図したとおりのセキュリティルールが書かれているかどうか、出力されたJSONをちゃんとチェックしたほうがいいと思います。結局、人の目でチェックしないと、自分は正しいと思って書いたけど、実際は正しくないみたいなことも起こりうると思います。
ちょっと長くなっちゃいましたけど、Realtime DBのほうは終わりで、次は、Cloud Storageです。
Cloud Storageは何かというと、画像や動画などの大きめのファイルのデータを保存するためのストレージです。これもSDKを通して、クライアントから直接ストレージに突っ込めます。
これはJSONじゃなくて、セキュリティルール用の独自言語が存在しています。
型定義はないんですけど、コメントや関数定義ができます。さっきのBoltみたいに、readはgetとlistに分割できるし、writeはcreate、update、deleteといった感じで分割できるので、記述しやすくなっています。
よくあるCloud Storageのセキュリティルールなんですけど、こういう感じでserviceというのを定義して、matchでbucket……変数を「ブラケット、bucket、ブラケット」という感じで書くと変数になって、isImageや、ファンクションを整理しています。
isImageのなかで何をしているのかというと、リソースサイズを見て、5メガバイトに制限するということや、コンテントタイプを見て、Imageしかアップロードさせないということも、こうしてセキュリティルールを書けば作れます。
あとは、createの時にメタデータにuidが入ってるかどうか、それがリクエストした人とちゃんと同じuidかどうか、updateする時も同じユーザーIDの人かどうか、deleteの時も、リクエストしてきたuidの人がちゃんと一致してるかどうかをチェックできます。
注意点として、GCSのアクセス制御は、裏側がGoogle Cloud Storageというものが使われています。これはCloud Storageのほうの設定で、例えば「このオブジェクトがパブリックのURLを付与する」というものがあるんですけど、それにチェックを入れると、そのパブリックURLからはアクセスできます。resource.data.visibilityがpublicになるんですね。
ここのreadがfalseになっていても、GCSのパブリックのURLが存在すると、そっちからは別にダウンロードできるよね、といったことになります。Google Cloud Storage側のACLなどの設定を、しっかりチェックしておく必要があります。
セキュリティルールと必ず1対1であるかというと、そういうわけではありません。各種設定に依存してくるので、Cloud StorageはそういうACLをちゃんとチェックしましょう。
次が、Cloud Firestoreですね。みんな「セキュリティルールをやるぞ!」と思った時、たぶんFirestoreが一番気になってるかなと思います。
Cloud Firestoreとは何か知らない人もいるとは思うので説明すると、Realtime DBの次世代のデータベースということになっていると思います。
ドキュメント指向で、基本的にはRealtime DBと同じことができます。なので、さっき説明したオフラインの書き込みもできるし、クライアントから直接データベースへの書き込みもできる。あと、変更を検知して、いろいろ処理するということもできます。
Realtime DBとの違いは、クエリとかがちょっと強化されていて、where文とかでもう少し賢いクエリを立てます。
さすがにMySQLみたいな、ガッツリSQLが書けるわけではないですけど、Realtime DBと比べればマシなクエリが書けます。
Slackのシャープステータスに入っている人を見るとわかると思うんですけど、 Realtime DBのステータスや、落ちたレポートとかが上がってきてると思います。Firestoreは安定感があるかなと(思います)。ただ、まだβで、USにしかリージョンがないので、本番で使えるかどうかはまだこれからかなという気がします。
Realtime DBとのセキュリティルール的な違いは、さっき説明したJSONではなく、Storageと同じように独自言語で書けることです。Storageとだいたい同じものだと思って大丈夫です。
さっき説明し忘れたんですけど、Realtime DBのセキュリティルールは、セキュリティルール内にIndexを書くこともあります。Firestoreにおいては、セキュリティルールとは分離して設定ができます。あと、サーバーの設定になるんですけど、IAMの設定もできます。
また、ワイルドカードの設定を除き、ルールがカスケード式ではないので、さっきのRealtime DBで説明した、上位層でreadをマッチして、下位層も全部許可される、みたいなことにはなりません。さっき説明したStorageと同じで、readはget、listに分割できるし、writeはcreate、update、deleteに分割できます。
これはざっくりしたサンプルなんですけど、isPersonMessageというファンクションを定義して、それを下のallow writeのほうで使っています。resource.keys().hasAll(['name'])とか、いろいろ便利な関数があります。
hasAllというのは……このリソースはnameプロパティを含んでなければいけないということをチェックできて、hasOnlyというのは、name、email以外のものが含まれているかどうかをチェックできます。name、email以外のものが含まれていると、これは失敗しますね。
あと、Realtime DBと同じように、クエリの制限ももちろんできます。query.limit <= 10というようにすると、10件に制限できます。
listにしているというのが、ポイントですね。
これはgetという関数が定義されています。何かというと、セキュリティルールは自分がアクセスしようとしているところのリソースをとろうとする時、すでにあるデータのリソースはそのまま取れるんですけど、別のところに存在するマスタとかをチェックしたい場合は、こういうgetなどを使って、別のパスに保存されているデータを読み出す必要があり、パスとかで読み出せます。getを使えば、referee == request.auth.uidとかでチェックできるわけですね。
ただ、getを使う時に注意しないといけない点があります。文字がかなり小さくて申し訳ないです。getやexistsなど別のパスにあるデータを読み出そうとすると、readのオペレーションがかかるので、その分コストがかかります。あと、getやexistsは呼び出し回数に制限があります。いまのところ、確か10回までしか呼べないという制限があったと思います。
次は、protobuf-rules-genという、また突拍子のないものが出てきましたが、これが何かを説明します。
protocol bufferというものがあります。protocol bufferはIDLを定義して、クライアントやサーバーなど、いろんなものとメッセージをするためのシリアライザーみたいなものです。
protobuf-rules-genはprotocol bufferから型定義を見て、それを検査してくれるセキュリティルールを生成するプラグインというものです。
さっき説明したんですけど、hasAllやhasOnlyというのは、結局手動で書かなければいけないんですけど、このあたりの設定を、protobuf-rules-genというものを使うと、protocol bufferの設定から簡単に生成することができます。
これがなんでうれしいかというのは、さっき説明した型定義ができないというところを、これで解消できるからです。たくさんプロパティがあるものだと、「それ全部、セキュリティルールを1個1個書いていくのか……」という思いが生まれちゃいます。(しかし)こういうものを活用していくと、簡単に書くことができます。
まとめとして、セキュリティルールは必ず設定しましょう。
開発のタイミングだと、「とりあえずセキュリティルールなしでもいいかな」みたいな感じで開発しちゃうと思うんですけど、デプロイする時や公開する時は、どうせセキュリティルールを設定しないと危ないことになるので、最初からセキュリティルールを書いておいたほうが楽です。セキュリティルールを簡単に、書きやすくするためのツールはいろいろあるので、そういうものを活用して、早めに早めにセキュリティルールは書いておいたほうがいいです。
説明を省いちゃったんですけど、Realtime DBとFirestoreにはシミュレータがあるので、それを使ってテストするのもいいんですけど、シミュレータはシミュレータで、本物ではありません。実際にE2Eテストとかを組み合わせて、セキュリティルールが十分正しいかどうかをテストしたほうがいいです。以上です。ありがとうございます。
(会場拍手)
※登壇者注:今は、ローカルエミュレーターがあるのでそれも使えます。https://firebase.google.com/docs/firestore/security/test-rules-emulator
関連タグ:
2024.11.13
週3日働いて年収2,000万稼ぐ元印刷屋のおじさん 好きなことだけして楽に稼ぐ3つのパターン
2024.11.21
40代〜50代の管理職が「部下を承認する」のに苦戦するわけ 職場での「傷つき」をこじらせた世代に必要なこと
2024.11.20
成果が目立つ「攻めのタイプ」ばかり採用しがちな職場 「優秀な人材」を求める人がスルーしているもの
2024.11.20
「元エースの管理職」が若手営業を育てる時に陥りがちな罠 順調なチーム・苦戦するチームの違いから見る、育成のポイント
2023.03.21
民間宇宙開発で高まる「飛行機とロケットの衝突」の危機...どうやって回避する?
2024.11.19
がんばっているのに伸び悩む営業・成果を出す営業の違い 『無敗営業』著者が教える、つい陥りがちな「思い込み」の罠
2024.11.18
20名の会社でGoogleの採用を真似するのはもったいない 人手不足の時代における「脱能力主義」のヒント
2024.11.11
自分の「本質的な才能」が見つかる一番簡単な質問 他者から「すごい」と思われても意外と気づかないのが才能
2024.11.13
“退職者が出た時の会社の対応”を従業員は見ている 離職防止策の前に見つめ直したい、部下との向き合い方
2024.11.11
「退職代行」を使われた管理職の本音と葛藤 メディアで話題、利用者が右肩上がり…企業が置かれている現状とは