![](https://images.logmi.jp/media/article/331348/images/main_image_428f593386a1100fe4799e824be362fcd0ef3ab1.jpg?w=600)
2025.02.03
創業125年のロート製薬が、新たな「気づき」を見出し続けられるわけ トヨタのカイゼンにならった「改鮮活動」の実践法
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
関連タグ:
2025.02.06
すかいらーく創業者が、社長を辞めて75歳で再起業したわけ “あえて長居させるコーヒー店”の経営に込めるこだわり
2025.02.03
「昔は富豪的プログラミングなんてできなかった」 21歳で「2ちゃんねる」を生んだひろゆき氏が語る開発の裏側
2025.02.03
手帳に書くだけで心が整うメンタルケアのコツ イライラ、モヤモヤ、落ち込んだ時の手帳の使い方
2025.02.04
日本企業にありがちな「生産性の低さ」の原因 メーカーの「ちょっとした改善」で勝負が決まる仕組みの落とし穴
PR | 2025.02.07
プロジェクトマネージャーは「無理ゲーを攻略するプレイヤー」 仕事を任せられない管理職のためのマネジメントの秘訣
2025.02.05
「納得しないと動けない部下」を変える3つのステップとは マネージャーの悩みを解消する会話のテクニック
2025.01.07
1月から始めたい「日記」を書く習慣 ビジネスパーソンにおすすめな3つの理由
2025.02.06
落合陽一氏や松尾豊氏の研究は社会に届いているか? ひろゆき氏が語るアカデミアの課題と展望
2025.02.05
エンジニアとして成功するための秘訣とは? ひろゆき氏が語る、自由な働き方を叶えるアプリ開発とキャリア戦略
2025.02.04
生成AI時代に差をつける思考法とは? ひろゆき氏が語る「真のエンジニア像」