2024.12.19
システムの穴を運用でカバーしようとしてミス多発… バグが大量発生、決算が合わない状態から業務効率化を実現するまで
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.12.20
日本の約10倍がん患者が殺到し、病院はキャパオーバー ジャパンハートが描く医療の未来と、カンボジアに新病院を作る理由
2024.12.19
12万通りの「資格の組み合わせ」の中で厳選された60の項目 532の資格を持つ林雄次氏の新刊『資格のかけ算』の見所
2024.12.16
32歳で成績最下位から1年でトップ営業になれた理由 売るテクニックよりも大事な「あり方」
2023.03.21
民間宇宙開発で高まる「飛行機とロケットの衝突」の危機...どうやって回避する?
PR | 2024.12.20
モンスター化したExcelが、ある日突然崩壊 昭和のガス工事会社を生まれ変わらせた、起死回生のノーコード活用術
2024.12.12
会議で発言しやすくなる「心理的安全性」を高めるには ファシリテーションがうまい人の3つの条件
2024.12.18
「社長以外みんな儲かる給与設計」にした理由 経営者たちが語る、優秀な人材集め・会社を発展させるためのヒント
2024.12.17
面接で「後輩を指導できなさそう」と思われる人の伝え方 歳を重ねるほど重視される経験の「ノウハウ化」
2024.12.13
ファシリテーターは「しゃべらないほうがいい」理由 入山章栄氏が語る、心理的安全性の高い場を作るポイント
2024.12.10
メールのラリー回数でわかる「評価されない人」の特徴 職場での評価を下げる行動5選
Climbers Startup JAPAN EXPO 2024 - 秋 -
2024.11.20 - 2024.11.21
『主体的なキャリア形成』を考える~資格のかけ算について〜
2024.12.07 - 2024.12.07
Startup CTO of the year 2024
2024.11.19 - 2024.11.19
社員の力を引き出す経営戦略〜ひとり一人が自ら成長する組織づくり〜
2024.11.20 - 2024.11.20
「確率思考」で未来を見通す 事業を成功に導く意思決定 ~エビデンス・ベースド・マーケティング思考の調査分析で事業に有効な予測手法とは~
2024.11.05 - 2024.11.05