yourmystar tech blog
著者: fulu 公開日:

セキュリティ ルールで安全に Firestore を使おう

この記事はユアマイスター アドベントカレンダー 2022の 8 日目の記事です。

はじめに

Firestoreはモバイルアプリケーションや Web アプリケーションのクライアントから直接アクセスすることができる NoSQL データベースです。そのため、データベースの接続先情報は公開されておりエンドユーザーが入手することができる情報になります。

悪意のあるユーザーがアクセスして好き勝手されないようにデータを守るための方法がセキュリティ ルールを書くことです。本記事ではデータを守るためのセキュリティ ルールの書き方を紹介します。

セキュリティ ルールを書く準備

アプリケーションのルートから firebase init firestore を実行して必要なファイルを生成してください。

firestore-sample
├─── .firebaserc
├─── firebase.json
├─── firestore.indexes.json
└─── firestore.rules

firestore.rules というファイルが生成されるので、ここにセキュリティ ルールを記入していきます。

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if false;
    }
  }
}

データを守る

データを守るために読み取り時の認証・認可と書き込み時の認証・認可スキーマ検証バリデーションが考慮すべきポイントです。

認証・認可

Firebase SDK を利用して Firestore に接続すると Authentication と連動した認証を行うことができます。認証状態であれば、request の auth フィールドに認証ユーザーの情報が格納されます。

allow read: if request.auth != null;

また、ドキュメントパスの一部を Authentication の ID(uid)にすることで以下のようなルールを書くことができます。(もちろん、ドキュメントの ID のフィールドと比較することもできます)

match /users/{uid} {
  allow read: if request.auth != null && request.auth.uid == uid;
}

スキーマ検証

Firestore は NoSQL でスキーマレスなデータベースではあるのですが、ユーザーに意図しないスキーマを設定されると不具合の原因になります。 不具合の発生を回避するために意図したキーのみがあるかの確認と値の型が正しいかの確認が必要です。

以下のドキュメントのスキーマを例に検証方法を紹介します。

// path: /user/{uid}

<uid>: {
  displayName: '山田 太郎',
  photo: {
    url: 'https://www.sample.com/profile.jpg',
  },
  createdAt: 2022/12/01 12:34:56,
  updatedAt: 2022/12/01 12:34:56,
}

各フィールドのキーの名前と値の型は以下のように検証します。

service cloud.firestore {
  // スキーマを検証する関数
  function isValid(user) {
    return user.keys().toSet() == ['displayName', 'photo', 'createdAt', 'updatedAt'].toSet()
      && staff.displayName is string
      && user.photo.keys().toSet() == ['url'].toSet()
      && user.photo.url is string
      && user.createdAt is timestamp
      && user.updatedAt is timestamp;
  }
  match /users/{uid} {
    // 自分のuserのみ作成できる
    allow create: if request.auth != null
      && request.auth.uid == uid
      && isValid(request.resource.data);
  }
}

バリデーション

スキーマ検証後、フィールドに対してバリデーションをかけることはよくあると思います。

例えば、displayName が 1 文字以上であるという要件があるとします。以下のようにスキーマ検証後にバリデーションをかけます。

service cloud.firestore {
  ・
  ・
  ・
  match /users/{uid} {
    // 自分のuserのみ作成できる
    allow create: if request.auth != null
      && request.auth.uid == uid
      && isValid(request.resource.data)
      // displayNameは1文字以上であること
      && request.resource.data.displayName.size() >= 1;
  }
}

さいごに

Firestore は手軽に使用できるデータベースである反面、セキュリティには十二分に気をつけてセキュリティルールを書いていく必要があります。 弊社テックリードの著書である実践 Firestoreは Firestore を使う前に読んでほしいおすすめの一冊です!

次回は Firebase Summit 2022 で発表があった新機能で記事を書こうかなっと思っています。また読んでもらえると嬉しいです!それでは!

ツイートするはてなブックマークに追加シェアする