Google berkomitmen untuk mendorong terwujudnya keadilan ras bagi komunitas Kulit Hitam. Lihat caranya.

Cara Kerja Aturan Keamanan

Keamanan dapat menjadi salah satu bagian paling kompleks dari proses pengembangan aplikasi. Pada sebagian besar aplikasi, developer harus membangun dan menjalankan server yang menangani autentikasi (siapa penggunanya) dan otorisasi (apa yang bisa dilakukan pengguna).

Aturan Keamanan Firebase menghapus lapisan tengah (server) dan memungkinkan Anda menentukan izin berbasis jalur untuk klien yang terhubung ke data Anda secara langsung. Gunakan panduan ini untuk mempelajari lebih lanjut tentang cara penerapan aturan pada permintaan yang masuk.

Pilih produk untuk mempelajari lebih lanjut tentang aturannya.

Cloud Firestore

Struktur dasar

Aturan Keamanan Firebase di Cloud Firestore dan Cloud Storage menggunakan struktur dan sintaksis berikut:

service <<name>> {
  // Match the resource path.
  match <<path>> {
    // Allow the request if the following conditions are true.
    allow <<methods>> : if <<condition>>
  }
}

Berikut konsep utama yang perlu dipahami saat mem-build aturan:

  • Permintaan: Metode atau beberapa metode yang dipanggil dalam pernyataan allow. Ini adalah metode yang Anda izinkan untuk berjalan. Metode standarnya adalah: get, list, create, update, dan delete. Metode read dan write yang praktis akan mengaktifkan akses baca dan tulis yang luas pada jalur database atau penyimpanan yang ditentukan.
  • Jalur: Lokasi database atau penyimpanan, direpresentasikan sebagai jalur URI.
  • Aturan: Pernyataan allow, berisi kondisi yang mengizinkan permintaan jika permintaan tersebut bernilai benar.

Aturan keamanan versi 2

Mulai bulan Mei 2019, aturan keamanan Firebase versi 2 kini tersedia. Aturan versi 2 mengubah perilaku karakter pengganti rekursif {name=**}. Anda harus menggunakan versi 2 jika berencana untuk menggunakan kueri grup koleksi. Anda harus memilih versi 2 dengan menerapkan rules_version = '2'; di baris pertama dalam aturan keamanan Anda:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {

Mencocokkan jalur

Semua pernyataan kecocokan harus mengarah ke dokumen, bukan koleksi. Pernyataan kecocokan dapat mengarah ke dokumen tertentu, seperti di match /cities/SF atau menggunakan karakter pengganti untuk mengarah ke dokumen apa pun di jalur yang ditentukan, seperti di match /cities/{city}.

Pada contoh di atas, pernyataan kecocokan menggunakan sintaksis karakter pengganti {city}. Artinya, aturan tersebut berlaku untuk setiap dokumen dalam koleksi cities, seperti /cities/SF atau /cities/NYC. Saat ekspresi allow dalam pernyataan kecocokan dievaluasi, variabel city akan diselesaikan menjadi nama dokumen kota, seperti SF atau NYC.

Mencocokkan subkoleksi

Data di Cloud Firestore disusun menjadi koleksi dokumen, dan setiap dokumen dapat memperluas hierarkinya hingga subkoleksi. Anda perlu memahami interaksi antara aturan keamanan dengan data hierarkis.

Pertimbangkan situasi saat setiap dokumen dalam koleksi cities berisi subkoleksi landmarks. Aturan keamanan hanya berlaku di jalur yang cocok, sehingga kontrol akses yang ditetapkan pada koleksi cities tidak berlaku untuk subkoleksi landmarks. Sebagai gantinya, tulis aturan eksplisit untuk mengontrol akses ke subkoleksi:

service cloud.firestore {
  match /databases/{database}/documents {
    match /cities/{city} {
      allow read, write: if <condition>;

        // Explicitly define rules for the 'landmarks' subcollection
        match /landmarks/{landmark} {
          allow read, write: if <condition>;
        }
    }
  }
}

Saat membuat pernyataan match bertingkat, jalur pernyataan match dalam selalu bersifat relatif terhadap jalur pernyataan match luar. Oleh karena itu, kumpulan aturan berikut adalah setara:

service cloud.firestore {
  match /databases/{database}/documents {
    match /cities/{city} {
      match /landmarks/{landmark} {
        allow read, write: if <condition>;
      }
    }
  }
}
service cloud.firestore {
  match /databases/{database}/documents {
    match /cities/{city}/landmarks/{landmark} {
      allow read, write: if <condition>;
    }
  }
}

Karakter pengganti rekursif

Jika Anda ingin menerapkan aturan ke hierarki dalam secara arbitrer, gunakan sintaksis karakter pengganti rekursif, {name=**}:

service cloud.firestore {
  match /databases/{database}/documents {
    // Matches any document in the cities collection as well as any document
    // in a subcollection.
    match /cities/{document=**} {
      allow read, write: if <condition>;
    }
  }
}

Saat menggunakan sintaksis karakter pengganti rekursif, variabel karakter pengganti akan memuat seluruh segmen jalur yang cocok, meskipun dokumen tersebut berada di subkoleksi bertingkat yang dalam. Misalnya, aturan yang tercantum di atas akan cocok dengan dokumen yang terletak di /cities/SF/landmarks/coit_tower, dan nilai variabel document akan menjadi SF/landmarks/coit_tower.

Namun, perlu diperhatikan bahwa perilaku karakter pengganti rekursif bergantung pada versi aturan.

Versi 1

Aturan keamanan menggunakan versi 1 secara default. Dalam versi 1, karakter pengganti rekursif cocok dengan satu atau beberapa item jalur. Karakter pengganti tersebut tidak cocok dengan jalur yang kosong, sehingga match /cities/{city}/{document=**} cocok dengan dokumen di subkoleksi, bukan di koleksi cities, sedangkan match /cities/{document=**} cocok dengan dokumen dalam koleksi dan subkoleksi cities.

Karakter pengganti rekursif harus ada di akhir pernyataan yang cocok.

Versi 2

Pada aturan keamanan versi 2, karakter pengganti rekursif cocok dengan nol atau beberapa item jalur. match/cities/{city}/{document=**} mencocokkan dokumen di subkoleksi apa pun serta dokumen di koleksi cities.

Anda harus ikut serta ke versi 2 dengan menambahkan rules_version = '2'; di bagian atas aturan keamanan Anda:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    // Matches any document in the cities collection as well as any document
    // in a subcollection.
    match /cities/{city}/{document=**} {
      allow read, write: if <condition>;
    }
  }
}

Anda dapat memiliki paling banyak satu karakter pengganti rekursif di setiap pernyataan yang cocok, tetapi dalam versi 2, Anda dapat menempatkan karakter pengganti ini di mana saja dalam pernyataan yang cocok. Contoh:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    // Matches any document in the songs collection group
    match /{path=**}/songs/{song} {
      allow read, write: if <condition>;
    }
  }
}

Jika menggunakan kueri grup koleksi, Anda harus menggunakan versi 2. Lihat bagian mengamankan kueri grup koleksi.

Pernyataan kecocokan yang tumpang tindih

Ada kemungkinan dokumen cocok dengan beberapa pernyataan match. Jika beberapa ekspresi allow cocok dengan suatu permintaan, akses akan diizinkan jika salah satu kondisi tersebut adalah true:

service cloud.firestore {
  match /databases/{database}/documents {
    // Matches any document in the 'cities' collection.
    match /cities/{city} {
      allow read, write: if false;
    }

    // Matches any document in the 'cities' collection or subcollections.
    match /cities/{document=**} {
      allow read, write: if true;
    }
  }
}

Pada contoh di atas, semua operasi baca dan tulis ke koleksi cities akan diizinkan karena aturan kedua selalu true, meskipun aturan pertama selalu false.

Batas aturan keamanan

Perhatikan batas berikut saat menangani aturan keamanan:

Batas Detail
Jumlah maksimum panggilan exists(), get(), dan getAfter() per permintaan
  • Sepuluh untuk permintaan dokumen tunggal dan permintaan kueri.
  • 20 untuk pembacaan, transaksi, dan penulisan batch multi-dokumen. Batas 10 sebelumnya juga berlaku untuk setiap operasi.

    Misalnya, bayangkan Anda membuat permintaan penulisan batch dengan 3 operasi penulisan dan aturan keamanan yang menggunakan 2 panggilan akses dokumen untuk memvalidasi setiap penulisan. Dalam hal ini, setiap penulisan menggunakan 2 dari 10 panggilan aksesnya dan permintaan penulisan batch menggunakan 6 dari 20 panggilan aksesnya.

Melebihi salah satu batas akan menyebabkan error izin ditolak.

Beberapa panggilan akses dokumen dapat di-cache, dan panggilan yang di-cache tidak diperhitungkan batasnya.

Kedalaman maksimum pernyataan match bertingkat 10
Panjang jalur maksimum, pada segmen jalur, yang diizinkan dalam sekumpulan pernyataan match bertingkat 100
Jumlah maksimum variabel tangkapan jalur yang diizinkan dalam sekumpulan pernyataan match bertingkat 20
Kedalaman maksimum panggilan fungsi 20
Jumlah maksimum argumen fungsi 7
Jumlah maksimum binding variabel let per fungsi 10
Jumlah maksimum panggilan fungsi siklis atau rekursif 0 &lpar;tidak diizinkan&rpar;
Jumlah maksimum ekspresi yang dievaluasi per permintaan 1.000
Ukuran maksimum kumpulan aturan Kumpulan aturan Verax harus mematuhi dua batas ukuran:
  • Batas 256 KB pada ukuran sumber teks kumpulan aturan Verax yang dipublikasikan dari Firebase console atau dari CLI menggunakan firebase deploy.
  • Batas 250 KB pada ukuran kumpulan aturan kompilasi yang dihasilkan saat Firebase memproses sumber Verax dan menjadikannya aktif di back-end.

Cloud Storage

Struktur dasar

Aturan Keamanan Firebase di Cloud Firestore dan Cloud Storage menggunakan struktur dan sintaksis berikut:

service <<name>> {
  // Match the resource path.
  match <<path>> {
    // Allow the request if the following conditions are true.
    allow <<methods>> : if <<condition>>
  }
}

Berikut konsep utama yang perlu dipahami saat mem-build aturan:

  • Permintaan: Metode atau beberapa metode yang dipanggil dalam pernyataan allow. Ini adalah metode yang Anda izinkan untuk berjalan. Metode standarnya adalah: get, list, create, update, dan delete. Metode read dan write yang praktis akan mengaktifkan akses baca dan tulis yang luas pada jalur database atau penyimpanan yang ditentukan.
  • Jalur: Lokasi database atau penyimpanan, direpresentasikan sebagai jalur URI.
  • Aturan: Pernyataan allow, berisi kondisi yang mengizinkan permintaan jika permintaan tersebut bernilai benar.

Mencocokkan jalur

Aturan Keamanan Storage match dengan jalur file yang digunakan untuk mengakses file di Cloud Storage. Aturan dapat match dengan jalur persisnya atau jalur karakter pengganti, dan aturan juga dapat dijadikan bertingkat. Jika tidak ada aturan yang cocok yang mengizinkan metode permintaan, atau jika kondisi bernilai false, permintaan akan ditolak.

Pencocokan persis

// Exact match for "images/profilePhoto.png"
match /images/profilePhoto.png {
  allow write: if <condition>;
}

// Exact match for "images/croppedProfilePhoto.png"
match /images/croppedProfilePhoto.png {
  allow write: if <other_condition>;
}

Pencocokan bertingkat

// Partial match for files that start with "images"
match /images {
  // Exact match for "images/profilePhoto.png"
  match /profilePhoto.png {
    allow write: if <condition>;
  }

  // Exact match for "images/croppedProfilePhoto.png"
  match /croppedProfilePhoto.png {
    allow write: if <other_condition>;
  }
}

Pencocokan karakter pengganti

Aturan juga dapat digunakan untuk match pola menggunakan karakter pengganti. Karakter pengganti adalah variabel bernama yang mewakili string tunggal, seperti profilePhoto.png atau beberapa segmen jalur, seperti images/profilePhoto.png.

Karakter pengganti dibuat dengan menambahkan tanda kurung kurawal di awal dan akhir nama karakter pengganti, misalnya {string}. Karakter pengganti beberapa segmen dapat dideklarasikan dengan menambahkan =** ke nama karakter pengganti, seperti {path=**}:

// Partial match for files that start with "images"
match /images {
  // Exact match for "images/*"
  // e.g. images/profilePhoto.png is matched
  match /{imageId} {
    // This rule only matches a single path segment (*)
    // imageId is a string that contains the specific segment matched
    allow read: if <condition>;
  }

  // Exact match for "images/**"
  // e.g. images/users/user:12345/profilePhoto.png is matched
  // images/profilePhoto.png is also matched!
  match /{allImages=**} {
    // This rule matches one or more path segments (**)
    // allImages is a path that contains all segments matched
    allow read: if <other_condition>;
  }
}

Jika beberapa aturan cocok dengan sebuah file, hasilnya adalah OR dari hasil semua evaluasi aturan. Artinya, jika aturan yang cocok dengan file bernilai true, hasilnya adalah true.

Pada aturan di atas, file "images/profilePhoto.png" dapat dibaca jika salah satu condition atau other_condition bernilai benar, sedangkan file "images/users/user:12345/profilePhoto.png" hanya bergantung pada hasil other_condition.

Variabel karakter pengganti dapat dirujuk dari dalam match yang memberikan nama file atau otorisasi jalur:

// Another way to restrict the name of a file
match /images/{imageId} {
  allow read: if imageId == "profilePhoto.png";
}

Aturan Keamanan Storage tidak menurun dan aturan hanya dievaluasi jika jalur permintaan cocok dengan jalur untuk aturan yang ditetapkan.

Evaluasi permintaan

Upload, download, perubahan metadata, dan penghapusan dievaluasi menggunakan request yang dikirim ke Cloud Storage. Variabel request berisi jalur file tempat permintaan dijalankan, waktu permintaan diterima, dan nilai resource baru jika permintaan tersebut adalah permintaan tulis. Header HTTP dan status autentikasi juga dicantumkan.

Objek request juga berisi ID unik pengguna dan payload Firebase Authentication di objek request.auth, yang akan dijelaskan lebih lanjut di bagian Autentikasidalam dokumen ini.

Daftar lengkap properti di objek request tersedia di bawah:

Properti Jenis Deskripsi
auth map<string, string> Saat pengguna login, memasukkan uid, ID unik pengguna, dan token, peta klaim JWT Firebase Authentication. Untuk kondisi lainnya, nilainya adalah null.
params map<string, string> Peta yang memuat parameter kueri permintaan.
path jalur path yang mewakili jalur tempat permintaan dijalankan.
resource map<string, string> Nilai resource baru, hanya ada pada permintaan write.
time timestamp Stempel waktu yang menunjukkan waktu server ketika permintaan dievaluasi.

Evaluasi resource

Saat mengevaluasi aturan, Anda mungkin juga ingin mengevaluasi metadata file yang sedang diupload, didownload, diubah, atau dihapus. Dengan begitu, Anda dapat membuat aturan yang rumit dan kuat untuk melakukan hal spesifik, seperti hanya mengizinkan upload file dengan jenis konten tertentu atau penghapusan file dengan ukuran lebih besar dari ukuran tertentu.

Aturan Keamanan Firebase untuk Cloud Storage menyediakan metadata file di objek resource, yang berisi key-value pair dari metadata yang muncul pada objek Cloud Storage. Properti ini dapat diinspeksi pada permintaan read atau write untuk memastikan integritas data.

Pada permintaan write (seperti upload, pembaruan metadata, dan penghapusan), selain objek resource, yang berisi metadata file untuk file yang saat ini ada di jalur permintaan, Anda juga dapat menggunakan objek request.resource, yang berisi subset metadata file yang akan ditulis jika operasi tulis diizinkan. Anda dapat menggunakan kedua nilai tersebut untuk memastikan integritas data atau memberlakukan pembatasan aplikasi, seperti jenis atau ukuran file.

Daftar lengkap properti di objek resource tersedia di bawah:

Properti Jenis Deskripsi
name string Nama lengkap objek
bucket string Nama bucket yang ditempati objek ini.
generation int GCS object generation untuk objek ini.
metageneration int GCS object metageneration untuk objek ini.
size int Ukuran objek, dalam byte.
timeCreated timestamp Stempel waktu yang menunjukkan kapan objek dibuat.
updated timestamp Stempel waktu yang menunjukkan kapan objek terakhir diperbarui.
md5Hash string Hash MD5 untuk objek ini.
crc32c string Hash crc32c untuk objek ini.
etag string etag yang terkait dengan objek ini.
contentDisposition string Disposisi konten yang terkait dengan objek ini.
contentEncoding string Encoding konten yang terkait dengan objek ini.
contentLanguage string Bahasa konten yang terkait dengan objek ini.
contentType string Jenis konten yang terkait dengan objek ini.
metadata map<string, string> Key-value pair untuk metadata kustom tambahan yang ditetapkan developer.

request.resource berisi semua properti di atas kecuali generation, metageneration, etag, timeCreated, dan updated.

Contoh Lengkap

Dengan menggabungkan semuanya, Anda dapat membuat contoh lengkap aturan untuk solusi penyimpanan gambar:

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

Realtime Database

Struktur dasar

Pada Realtime Database, Aturan Keamanan Firebase terdiri dari ekspresi serupa JavaScript yang terdapat pada dokumen JSON.

Aturan tersebut menggunakan sintaksis berikut:

{
  "rules": {
    "<<path>>": {
    // Allow the request if the condition for each method is true.
      ".read": <<condition>>,
      ".write": <<condition>>,
      ".validate": <<condition>>
    }
  }
}

Aturan memiliki tiga elemen dasar, yaitu:

  • Jalur: Lokasi database Ini mencerminkan struktur JSON database Anda.
  • Permintaan: Ini adalah metode yang digunakan aturan untuk memberikan akses. Aturan read dan write memberikan akses baca dan tulis yang luas, sedangkan aturan validate bertindak sebagai verifikasi sekunder untuk memberikan akses berdasarkan data yang masuk atau yang sudah ada.
  • Kondisi: Kondisi yang mengizinkan permintaan jika permintaan tersebut bernilai benar.

Cara penerapan aturan pada jalur

Pada Realtime Database, Aturan berlaku secara atomis. Artinya, aturan di node induk tingkat yang lebih tinggi menggantikan aturan di node turunan yang lebih terperinci. Selain itu, aturan di node yang lebih dalam tidak dapat memberi akses ke jalur induk. Anda tidak dapat memperbaiki atau mencabut akses di path yang lebih dalam pada struktur database jika Anda sudah memberikan akses ke salah satu path induk.

Perhatikan aturan berikut ini:

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

Struktur keamanan ini memungkinkan /bar/ untuk dibaca jika /foo/ berisi baz turunan dengan nilai true. Aturan ".read": false pada bagian /foo/bar/ tidak berpengaruh di sini, karena akses tidak dapat dicabut oleh jalur turunan.

Meski terlihat tidak intuitif, struktur ini adalah bagian dari bahasa aturan yang andal. Oleh karena itu, hak istimewa akses yang sangat kompleks dapat diterapkan dengan usaha minimal. Ini sangat berguna untuk keamanan berbasis pengguna.

Namun, aturan .validate tidak bersifat menurun. Semua aturan validasi harus terpenuhi di semua tingkat hierarkinya agar operasi tulis diizinkan.

Selain itu, karena aturan tidak berlaku untuk jalur induk, operasi baca atau tulis akan gagal jika lokasi yang diminta atau lokasi induk yang memberikan akses tidak memiliki aturan. Sekalipun setiap jalur turunan yang terpengaruh bisa diakses, operasi baca di lokasi induk tidak akan dapat dilakukan. Perhatikan struktur ini:

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

Tanpa memahami bahwa aturan dievaluasi secara atomis, mengambil jalur /records/ mungkin seolah akan menampilkan rec1 dan bukan rec2. Namun, hasil sesungguhnya adalah error:

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
}];
Swift
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
  });
});
REST
curl https://docs-examples.firebaseio.com/rest/records/
# response returns a PERMISSION_DENIED error

Karena operasi baca di /records/ bersifat atomis, dan tidak ada aturan baca yang memberikan akses ke semua data pada bagian /records/, tindakan ini akan menghasilkan error PERMISSION_DENIED. Jika aturan ini dievaluasi dalam simulator keamanan di Firebase console, kita dapat melihat bahwa operasi baca ditolak:

Attempt to read /records with auth=Success(null)
    /
    /records

No .read rule allowed the operation.
Read was denied.

Operasi tersebut ditolak karena tidak ada aturan baca yang mengizinkan akses ke jalur /records/. Namun, perhatikan bahwa aturan untuk rec1 tidak pernah dievaluasi karena tidak berada di jalur yang diminta. Untuk mengambil rec1, kita perlu mengaksesnya secara langsung:

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!
}];
Swift
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
  }
});
REST
curl https://docs-examples.firebaseio.com/rest/records/rec1
# SUCCESS!

Variabel lokasi

Aturan Realtime Database mendukung variabel $location untuk mencocokkan segmen jalur. Gunakan awalan $ di depan segmen jalur untuk mencocokkan aturan dengan node turunan di sepanjang jalur.

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

Anda juga dapat menggunakan $variable secara bersamaan dengan nama jalur tetap.

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