Firebase Summit で発表されたすべての情報をご覧ください。Firebase を使用してアプリ開発を加速し、自信を持ってアプリを実行する方法を紹介しています。詳細

データ検証

Firebase セキュリティ ルールを使用して、データベースまたはストレージ バケット内の既存のデータに基づいて、条件付きで新しいデータを書き込むことができます。書き込まれる新しいデータに基づいて書き込みを制限することにより、データの検証を実施するルールを作成することもできます。既存のデータを使用してセキュリティ条件を作成するルールの詳細については、以下をお読みください。

データ検証ルールの詳細については、各セクションで製品を選択してください。

新規データの制限

クラウド ファイアストア

特定のフィールドを含むドキュメントが作成されないようにする場合は、そのフィールドをallow条件に含めることができます。たとえば、 rankingフィールドを含むドキュメントの作成を拒否する場合は、 create条件でそれを禁止します。

  service cloud.firestore {
    match /databases/{database}/documents {
      // Disallow
      match /cities/{city} {
        allow create: if !("ranking" in request.resource.data)
      }
    }
  }

リアルタイム データベース

特定の値を含むデータがデータベースに追加されないようにする場合は、その値をルールに含めて、書き込みを禁止します。たとえば、 ranking rankingを含むドキュメントの書き込みを禁止します。

  {
    "rules": {
      // Write is allowed for all paths
      ".write": true,
      // Allows writes only if new data doesn't include a `ranking` child value
      ".validate": "!newData.hasChild('ranking')
    }
  }

クラウドストレージ

特定のメタデータを含むファイルが作成されないようにする場合は、メタデータをallow条件に含めることができます。たとえば、 rankingメタデータを含むファイルの作成を拒否する場合は、 create条件で禁止します。

  service firebase.storage {
    match /b/{bucket}/o {
      match /files/{allFiles=**} {
      // Disallow
        allow create: if !("ranking" in request.resource.metadata)
      }
    }
  }

Firebase セキュリティ ルールで既存のデータを使用する

クラウド ファイアストア

多くのアプリは、アクセス制御情報をデータベース内のドキュメントのフィールドとして保存します。 Cloud Firestore セキュリティ ルールは、ドキュメント データに基づいてアクセスを動的に許可または拒否できます。

  service cloud.firestore {
    match /databases/{database}/documents {
      // Allow the user to read data if the document has the 'visibility'
      // field set to 'public'
      match /cities/{city} {
        allow read: if resource.data.visibility == 'public';
      }
    }
  }

resource変数は要求されたドキュメントを参照し、 resource.dataはドキュメントに保存されているすべてのフィールドと値のマップです。 resource変数の詳細については、リファレンス ドキュメントを参照してください。

データを書き込むときに、受信データを既存のデータと比較したい場合があります。これにより、フィールドが変更されていないこと、フィールドが 1 つだけ増加したこと、または新しい値が少なくとも 1 週間先であることを確認することができます。この場合、ルールセットが保留中の書き込みを許可している場合、 request.resource変数にはドキュメントの将来の状態が含まれます。ドキュメント フィールドのサブセットのみを変更するupdate操作の場合、 request.resource変数には操作後の保留中のドキュメント状態が含まれます。 request.resourceのフィールド値をチェックして、不要または不整合なデータ更新を防ぐことができます。

   service cloud.firestore {
     match /databases/{database}/documents {
      // Make sure all cities have a positive population and
      // the name is not changed
      match /cities/{city} {
        allow update: if request.resource.data.population > 0
                      && request.resource.data.name == resource.data.name;
      }
    }
  }

リアルタイム データベース

Realtime Database では、 .validateルールを使用してデータ構造を適用し、データの形式と内容を検証します。ルールは、 .writeルールがアクセスを許可することを確認した後、 .validateルールを実行します。

.validateルールはカスケードしません。ルール内のいずれかのパスまたはサブパスで検証ルールが失敗した場合、書き込み操作全体が拒否されます。さらに、検証定義は null 以外の値のみをチェックし、その後、データを削除する要求をすべて無視します。

次の.validateルールを検討してください。

  {
    "rules": {
      // write is allowed for all paths
      ".write": true,
      "widget": {
        // a valid widget must have attributes "color" and "size"
        // allows deleting widgets (since .validate is not applied to delete rules)
        ".validate": "newData.hasChildren(['color', 'size'])",
        "size": {
          // the value of "size" must be a number between 0 and 99
          ".validate": "newData.isNumber() &&
                        newData.val() >= 0 &&
                        newData.val() <= 99"
        },
        "color": {
          // the value of "color" must exist as a key in our mythical
          // /valid_colors/ index
          ".validate": "root.child('valid_colors/' + newData.val()).exists()"
        }
      }
    }
  }

上記のルールを使用してデータベースへの書き込み要求を行うと、次の結果が得られます。

JavaScript
var ref = db.ref("/widget");

// PERMISSION_DENIED: does not have children color and size
ref.set('foo');

// PERMISSION DENIED: does not have child color
ref.set({size: 22});

// PERMISSION_DENIED: size is not a number
ref.set({ size: 'foo', color: 'red' });

// SUCCESS (assuming 'blue' appears in our colors list)
ref.set({ size: 21, color: 'blue'});

// If the record already exists and has a color, this will
// succeed, otherwise it will fail since newData.hasChildren(['color', 'size'])
// will fail to validate
ref.child('size').set(99);
Objective-C
注:この Firebase 製品は、App Clip ターゲットでは使用できません。
FIRDatabaseReference *ref = [[[FIRDatabase database] reference] child: @"widget"];

// PERMISSION_DENIED: does not have children color and size
[ref setValue: @"foo"];

// PERMISSION DENIED: does not have child color
[ref setValue: @{ @"size": @"foo" }];

// PERMISSION_DENIED: size is not a number
[ref setValue: @{ @"size": @"foo", @"color": @"red" }];

// SUCCESS (assuming 'blue' appears in our colors list)
[ref setValue: @{ @"size": @21, @"color": @"blue" }];

// If the record already exists and has a color, this will
// succeed, otherwise it will fail since newData.hasChildren(['color', 'size'])
// will fail to validate
[[ref child:@"size"] setValue: @99];
迅速
注:この Firebase 製品は、App Clip ターゲットでは使用できません。
var ref = FIRDatabase.database().reference().child("widget")

// PERMISSION_DENIED: does not have children color and size
ref.setValue("foo")

// PERMISSION DENIED: does not have child color
ref.setValue(["size": "foo"])

// PERMISSION_DENIED: size is not a number
ref.setValue(["size": "foo", "color": "red"])

// SUCCESS (assuming 'blue' appears in our colors list)
ref.setValue(["size": 21, "color": "blue"])

// If the record already exists and has a color, this will
// succeed, otherwise it will fail since newData.hasChildren(['color', 'size'])
// will fail to validate
ref.child("size").setValue(99);
ジャワ
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference ref = database.getReference("widget");

// PERMISSION_DENIED: does not have children color and size
ref.setValue("foo");

// PERMISSION DENIED: does not have child color
ref.child("size").setValue(22);

// PERMISSION_DENIED: size is not a number
Map<String,Object> map = new HashMap<String, Object>();
map.put("size","foo");
map.put("color","red");
ref.setValue(map);

// SUCCESS (assuming 'blue' appears in our colors list)
map = new HashMap<String, Object>();
map.put("size", 21);
map.put("color","blue");
ref.setValue(map);

// If the record already exists and has a color, this will
// succeed, otherwise it will fail since newData.hasChildren(['color', 'size'])
// will fail to validate
ref.child("size").setValue(99);
休み
# PERMISSION_DENIED: does not have children color and size
curl -X PUT -d 'foo' \
https://docs-examples.firebaseio.com/rest/securing-data/example.json

# PERMISSION DENIED: does not have child color
curl -X PUT -d '{"size": 22}' \
https://docs-examples.firebaseio.com/rest/securing-data/example.json

# PERMISSION_DENIED: size is not a number
curl -X PUT -d '{"size": "foo", "color": "red"}' \
https://docs-examples.firebaseio.com/rest/securing-data/example.json

# SUCCESS (assuming 'blue' appears in our colors list)
curl -X PUT -d '{"size": 21, "color": "blue"}' \
https://docs-examples.firebaseio.com/rest/securing-data/example.json

# If the record already exists and has a color, this will
# succeed, otherwise it will fail since newData.hasChildren(['color', 'size'])
# will fail to validate
curl -X PUT -d '99' \
https://docs-examples.firebaseio.com/rest/securing-data/example/size.json

クラウドストレージ

ルールを評価するときに、アップロード、ダウンロード、変更、または削除されるファイルのメタデータを評価することもできます。これにより、特定のコンテンツ タイプのファイルのみをアップロードしたり、特定のサイズを超えるファイルのみを削除したりするなどの複雑で強力なルールを作成できます。

resourceオブジェクトには、Cloud Storage オブジェクトに表示されるファイル メタデータを含むキーと値のペアが含まれています。これらのプロパティは、 readまたはwrite要求で検査して、データの整合性を確保できます。 resourceオブジェクトは、Cloud Storage バケット内の既存のファイルのメタデータをチェックします。

  service firebase.storage {
    match /b/{bucket}/o {
      match /images {
        match /{allImages=**} {
          // Allow reads if a custom 'visibility' field is set to 'public'
          allow read: if resource.metadata.visibility == 'public';
        }
      }
    }
  }

writeリクエスト (アップロード、メタデータの更新、削除など) でrequest.resourceオブジェクトを使用することもできますrequest.resourceオブジェクトは、 writeが許可されている場合に書き込まれるファイルからメタデータを取得します。

これら 2 つの値を使用して、不要な更新や一貫性のない更新を防止したり、ファイルの種類やサイズなどのアプリケーションの制約を適用したりできます。

  service firebase.storage {
    match /b/{bucket}/o {
      match /images {
        // Cascade read to any image type at any path
        match /{allImages=**} {
          allow read;
        }

        // Allow write files to the path "images/*", subject to the constraints:
        // 1) File is less than 5MB
        // 2) Content type is an image
        // 3) Uploaded content type matches existing content type
        // 4) File name (stored in imageId wildcard variable) is less than 32 characters
        match /{imageId} {
          allow write: if request.resource.size < 5 * 1024 * 1024
                       && request.resource.contentType.matches('image/.*')
                       && request.resource.contentType == resource.contentType
                       && imageId.size() < 32
        }
      }
    }
  }

resourceオブジェクトのプロパティの完全なリストは、リファレンス ドキュメントで入手できます。