このページは Cloud Translation API によって翻訳されました。
Switch to English

Realtime Databaseルール言語のコア構文を学ぶ

Firebase Realtime Databaseのセキュリティルールを使用すると、データベースに保存されているデータへのアクセスを制御できます。柔軟なルール構文により、データベースへのすべての書き込みから個々のノードでの操作まで、あらゆるものに一致するルールを作成できます。

Realtime Database Security Rulesは、データベースの宣言的な構成です。つまり、ルールは製品ロジックとは別に定義されます。これには多くの利点があります。クライアントはセキュリティの実施に責任を負いません。バグのある実装はデータを危険にさらしません。そしておそらく最も重要なこととして、サーバーなどの中間レフェリーがデータを世界中から保護する必要はありません。

このトピックでは、完全なルールセットの作成に使用されるRealtime Databaseセキュリティルールの基本的な構文と構造について説明します。

セキュリティルールの構造化

Realtime Databaseセキュリティルールは、JSONドキュメントに含まれるJavaScriptのような式で構成されます。ルールの構造は、データベースに保存したデータの構造に従う必要があります。

基本ルールは、保護されるノードのセット 、関連するアクセス方法 (読み取り、書き込みなど)、およびアクセスが許可または拒否される条件を 識別します。以下の例では、 条件は単純なtrueおよびfalseステートメントですが、次のトピックでは、条件を表現するためのより動的な方法について説明します。

我々は確保しようとしているのであれば、例えば、 child_nodeparent_node 、フォローへの一般的な構文は次のとおりです。

{
  "rules": {
    "parent_node": {
      "child_node": {
        ".read": <condition>,
        ".write": <condition>,
        ".validate": <condition>,
      }
    }
  }
}

このパターンを適用してみましょう。たとえば、メッセージのリストを追跡していて、次のようなデータがあるとします。

{
  "messages": {
    "message0": {
      "content": "Hello",
      "timestamp": 1405704370369
    },
    "message1": {
      "content": "Goodbye",
      "timestamp": 1405704395231
    },
    ...
  }
}

ルールも同様に構成する必要があります。このデータ構造にとって意味のある読み取り専用セキュリティの一連のルールを次に示します。この例は、ルールが適用されるデータベースノードを指定する方法と、それらのノードでルールを評価するための条件を示しています。

{
  "rules": {
    // For requests to access the 'messages' node...
    "messages": {
      // ...and the individual wildcarded 'message' nodes beneath
      // (we'll cover wildcarding variables more a bit later)....
      "$message": {

        // For each message, allow a read operation if <condition>. In this
        // case, we specify our condition as "true", so read access is always granted.
        ".read": "true",

        // For read-only behavior, we specify that for write operations, our
        // condition is false.
        ".write": "false"
      }
    }
  }
}

基本的なルール操作

データに対して実行される操作のタイプに基づいてセキュリティを実施するためのルールには、 .write.read 、および.validate 3つのタイプがあります。以下は、その目的の簡単な要約です。

ルールの種類
。読んだ ユーザーによるデータの読み取りが許可されるかどうか、および許可される場合について説明します。
。書く データの書き込みが許可されるかどうか、および許可される場合について説明します。
。検証 正しくフォーマットされた値の外観、子属性があるかどうか、およびデータ型を定義します。

ワイルドカードキャプチャ変数

すべてのルールステートメントはノードを指します。ステートメントは、特定のノードを指すか、または$ワイルドカードキャプチャ変数を使用して、階層のレベルでノードのセットを指すことができます。これらのキャプチャ変数を使用して、後続のルールステートメント内で使用するノードキーの値を保存します。この手法を使用すると、より複雑なルール条件を記述できます。これについては、次のトピックで詳しく説明します。

{
  "rules": {
    "rooms": {
      // this rule applies to any child of /rooms/, the key for each room id
      // is stored inside $room_id variable for reference
      "$room_id": {
        "topic": {
          // the room's topic can be changed if the room id has "public" in it
          ".write": "$room_id.contains('public')"
        }
      }
    }
  }
}

動的$変数は、定数パス名と並行して使用することもできます。この例では、 $other変数を使用して、 widget titlecolor以外の子がないことを確認する.validateルールを宣言していwidget 。追加の子が作成される結果となる書き込みは失敗します。

{
  "rules": {
    "widget": {
      // a widget can have a title or color attribute
      "title": { ".validate": true },
      "color": { ".validate": true },

      // but no other child paths are allowed
      // in this case, $other means any key excluding "title" and "color"
      "$other": { ".validate": false }
    }
  }
}

ルールカスケードの読み取りと書き込み

.readルールと.writeルールはトップダウンで機能し、浅いルールが深いルールをオーバーライドします。ルールが特定のパスで読み取りまたは書き込み権限を許可する場合、そのルールはその下のすべての子ノードへのアクセスも許可します次の構造を考えてみましょう。

{
  "rules": {
     "foo": {
        // allows read to /foo/*
        ".read": "data.child('baz').val() === true",
        "bar": {
          /* ignored, since read was allowed already */
          ".read": false
        }
     }
  }
}

このセキュリティ構造により、 /bar/ /foo/に値truebazが含まれているときはいつでも、 /bar/を読み取ることができtrue".read": false /foo/bar/下の".read": falseルールは、子パスによってアクセスを取り消すことができないため、ここでは効果がありません。

直感的にはすぐに見えないかもしれませんが、これはルール言語の強力な部分であり、非常に複雑なアクセス権限を最小限の労力で実装できます。これについては、このガイドの後半でユーザーベースのセキュリティについて説明するときに説明します。

.validateルールはカスケードされないことに注意してください。書き込みを許可するには、すべての検証ルールが階層のすべてのレベルで満たされている必要があります。

ルールはフィルターではない

ルールはアトミックな方法で適用されます。つまり、その場所または親の場所にアクセスを許可するルールがない場合、読み取りまたは書き込み操作はすぐに失敗します。影響を受けるすべての子パスにアクセスできる場合でも、親の場所での読み取りは完全に失敗します。この構造を考えてみましょう:

{
  "rules": {
    "records": {
      "rec1": {
        ".read": true
      },
      "rec2": {
        ".read": false
      }
    }
  }
}

ルールがアトミックに評価されることを理解しないと、 /records/パスをフェッチするとrec1が返され、 rec1は返されないように見えることがありrec2 。ただし、実際の結果はエラーです。

JavaScript
var db = firebase.database();
db.ref("records").once("value", function(snap) {
  // success method is not called
}, function(err) {
  // error callback triggered with PERMISSION_DENIED
});
Objective-C
FIRDatabaseReference *ref = [[FIRDatabase database] reference];
[[_ref child:@"records"] observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  // success block is not called
} withCancelBlock:^(NSError * _Nonnull error) {
  // cancel block triggered with PERMISSION_DENIED
}];
迅速
var ref = FIRDatabase.database().reference()
ref.child("records").observeSingleEventOfType(.Value, withBlock: { snapshot in
    // success block is not called
}, withCancelBlock: { error in
    // cancel block triggered with PERMISSION_DENIED
})
ジャワ
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference ref = database.getReference("records");
ref.addListenerForSingleValueEvent(new ValueEventListener() {
  @Override
  public void onDataChange(DataSnapshot snapshot) {
    // success method is not called
  }

  @Override
  public void onCancelled(FirebaseError firebaseError) {
    // error callback triggered with PERMISSION_DENIED
  });
});
残り
curl https://docs-examples.firebaseio.com/rest/records/
# response returns a PERMISSION_DENIED error

/records/での読み取り操作はアトミックであり、 /records/下のすべてのデータへのアクセスを許可する読み取りルールがないため、これはPERMISSION_DENIEDエラーをスローします。 Firebaseコンソールのセキュリティシミュレータでこのルールを評価すると、 /records/パスへのアクセスを許可する読み取りルールがないため、読み取り操作が拒否されたことがわかります。ただし、 rec1のルールは要求したパスになかったため、評価されなかったことに注意してください。 rec1をフェッチrec1 、それに直接アクセスする必要があります。

JavaScript
var db = firebase.database();
db.ref("records/rec1").once("value", function(snap) {
  // SUCCESS!
}, function(err) {
  // error callback is not called
});
Objective-C
FIRDatabaseReference *ref = [[FIRDatabase database] reference];
[[ref child:@"records/rec1"] observeSingleEventOfType:FEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
    // SUCCESS!
}];
迅速
var ref = FIRDatabase.database().reference()
ref.child("records/rec1").observeSingleEventOfType(.Value, withBlock: { snapshot in
    // SUCCESS!
})
ジャワ
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference ref = database.getReference("records/rec1");
ref.addListenerForSingleValueEvent(new ValueEventListener() {
  @Override
  public void onDataChange(DataSnapshot snapshot) {
    // SUCCESS!
  }

  @Override
  public void onCancelled(FirebaseError firebaseError) {
    // error callback is not called
  }
});
残り
curl https://docs-examples.firebaseio.com/rest/records/rec1
# SUCCESS!

重複するステートメント

1つのノードに複数のルールを適用することが可能です。複数のルール式がノードを識別する場合、条件のいずれかfalse場合、アクセス方法は拒否されfalse

{
  "rules": {
    "messages": {
      // A rule expression that applies to all nodes in the 'messages' node
      "$message": {
        ".read": "true",
        ".write": "true"
      },
      // A second rule expression applying specifically to the 'message1` node
      "message1": {
        ".read": "false",
        ".write": "false"
      }
    }
  }
}

上記の例では、最初のルールは常にtrueにもかかわらず、2番目のルールは常にfalseであるため、 message1ノードへの読み取りは拒否されtrue

次のステップ

Firebase Realtime Databaseセキュリティルールの理解を深めることができます。