Catch up on everything we announced at this year's Firebase Summit. Learn more

リアルタイムデータベースルール言語のコア構文を学ぶ

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

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

このトピックでは、完全なルールセットを作成するために使用される基本的な構文と構造のリアルタイムデータベースセキュリティルールについて説明します。

セキュリティルールの構築

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

基本的なルールは関与を確保するためのアクセス方法(例えば、読み取り、書き込み)をノードの集合を特定し、アクセスが許可または拒否される条件。次の例では、私たちの条件は簡単になりtruefalseのステートメントが、次のトピックでは、我々は条件を表現するために、よりダイナミックな方法をカバーします。

我々は確保しようとしているのであれば、例えば、 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"
      }
    }
  }
}

基本的なルールの操作

:データ上で実行されている操作の種類に基づいてセキュリティを強化するためのルールの3つのタイプがあります.write.read 、および.validate 。これらの目的の簡単な要約は次のとおりです。

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

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

すべてのルールステートメントはノードを指します。声明は、特定のノードを指すか、使用することができます$階層のレベルのノードのセットを指すようにワイルドカードキャプチャ変数を。これらのキャプチャ変数を使用して、後続のルールステートメント内で使用するノードキーの値を格納します。この技術は、あなたが、私たちは次のトピックで詳しく取り上げる何かを、より複雑なルール条件を記述することができます。

{
  "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宣言するために変数を.validateルールをすることを確実にwidget以外の子供持っていないtitlecolor 。追加の子が作成される結果となる書き込みは失敗します。

{
  "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/子が含まbaz値とtrue".read": falseルールの下で/foo/bar/アクセスは、子のパスによって取り消すことができないため、ここでは効果がありません。

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

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

ルールはフィルターではありません

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

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

ルールがアトミックに評価されることを理解することなく、それはフェッチのように見えるかもしれません/records/パスを返します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
注:このFirebase製品は、Appクリップ対象では使用できません。
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
}];
迅速
注:このFirebase製品は、Appクリップ対象では使用できません。
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
})
Java
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 、我々はそれを直接アクセスする必要があります:

JavaScript
var db = firebase.database();
db.ref("records/rec1").once("value", function(snap) {
  // SUCCESS!
}, function(err) {
  // error callback is not called
});
Objective-C
注:このFirebase製品は、Appクリップ対象では使用できません。
FIRDatabaseReference *ref = [[FIRDatabase database] reference];
[[ref child:@"records/rec1"] observeSingleEventOfType:FEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
    // SUCCESS!
}];
迅速
注:このFirebase製品は、Appクリップ対象では使用できません。
var ref = FIRDatabase.database().reference()
ref.child("records/rec1").observeSingleEventOfType(.Value, withBlock: { snapshot in
    // SUCCESS!
})
Java
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

{
  "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"
      }
    }
  }
}

上記の例では、読み込みにmessage1第二のルールは常にあるので、拒否されるノードfalse最初のルールは常にあるにもかかわらず、 true

次のステップ

FirebaseRealtimeデータベースのセキュリティルールについての理解を深めることができます。

  • ルール言語、ダイナミックの次の主要な概念を学ぶの条件、あなたのルールチェックのユーザ認証を聞かせて、既存の着信データを比較し、入力データを検証し、クライアントからのクエリの構造をチェックして、より多くの。

  • 一般的なセキュリティのユースケースと確認したアドレスにそれらことFirebaseセキュリティルールの定義を