Bahasa Aturan Keamanan

Aturan Keamanan Firebase menggunakan bahasa yang fleksibel, andal, dan kustom yang mendukung berbagai tingkat kerumitan dan perincian. Anda dapat membuat Aturan yang sespesifik atau seumum mungkin untuk aplikasi Anda. Aturan Realtime Database menggunakan sintaksis yang serupa dengan JavaScript dalam struktur JSON. Aturan Cloud Firestore dan Cloud Storage menggunakan bahasa berdasarkan Common Expression Language (CEL), yang dikembangkan dari CEL dengan pernyataan match dan allow yang mendukung akses yang diberikan secara bersyarat.

Namun, mengingat ini adalah bahasa kustom, tentu diperlukan proses pembelajaran. Gunakan panduan ini untuk lebih memahami bahasa Aturan sembari mempelajari lebih dalam aturan yang lebih kompleks.

Pilih produk untuk mempelajari lebih lanjut aturannya.

Struktur dasar

Cloud Firestore

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: Satu 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 kondisi tersebut bernilai benar.

Baca penjelasan selengkapnya mengenai setiap konsep tersebut di bawah.

Cloud Storage

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: Satu 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 kondisi tersebut bernilai benar.

Baca penjelasan selengkapnya mengenai setiap konsep tersebut di bawah.

Realtime Database

Pada Realtime Database, Aturan Keamanan Firebase terdiri dari ekspresi serupa JavaScript yang terdapat dalam 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 kondisi tersebut bernilai benar.

Pembuatan aturan

Cloud Firestore

Berikut elemen dasar aturan di Cloud Firestore dan Cloud Storage:

  • Deklarasi service: Mendeklarasikan pada produk Firebase apa aturan tersebut diterapkan.
  • Blok match: Menentukan jalur dalam database atau bucket penyimpanan tempat aturan tersebut diterapkan.
  • Pernyataan allow: Menentukan kondisi untuk memberikan akses, yang dibedakan berdasarkan metode. Metode yang didukung meliputi: get, list, create, update, delete, dan metode read dan write yang praktis.
  • Deklarasi function opsional: Memberikan kemampuan untuk mengombinasikan dan menggabungkan kondisi untuk digunakan pada beberapa aturan.

service berisi satu atau beberapa blok match dengan pernyataan allow yang menetapkan kondisi yang memberikan akses ke permintaan. Variabel request dan resource dapat diterapkan dalam kondisi aturan. Bahasa Aturan Keamanan Firebase juga mendukung deklarasi function.

Versi sintaksis

Pernyataan syntax menunjukkan versi bahasa Aturan Firebase yang digunakan untuk menulis sumber. Versi bahasa terbaru adalah v2.

rules_version = '2';
service cloud.firestore {
...
}

Jika tidak ada pernyataan rules_version yang diberikan, aturan Anda akan dievaluasi menggunakan mesin v1.

Service

Deklarasi service menentukan pada produk atau layanan Firebase apa aturan Anda diterapkan. Anda hanya dapat menyertakan satu deklarasi service per file sumber.

Cloud Firestore

service cloud.firestore {
 // Your 'match' blocks with their corresponding 'allow' statements and
 // optional 'function' declarations are contained here
}

Cloud Storage

service firebase.storage {
  // Your 'match' blocks with their corresponding 'allow' statements and
  // optional 'function' declarations are contained here
}

Aturan yang ditetapkan untuk Cloud Firestore dan Cloud Storage menggunakan Firebase CLI harus disimpan dalam file terpisah.

Match

Blok match mendeklarasikan pola path yang dicocokkan dengan jalur operasi yang diminta (request.path yang masuk). Isi match harus memiliki satu atau beberapa blok match bertingkat, pernyataan allow, atau deklarasi function. Jalur dalam blok match bertingkat bersifat relatif terhadap jalur dalam blok match induk.

Pola path adalah nama serupa direktori yang dapat mengandung variabel atau karakter pengganti. Dengan pola path, pencocokan segmen jalur tunggal dan segmen multi-jalur dapat dilakukan. Variabel apa pun yang terikat dengan path terlihat dalam cakupan match atau cakupan bertingkat tempat path dideklarasikan.

Kecocokan dengan pola path dapat bersifat sebagian atau penuh:

  • Kecocokan sebagian: Awalan pola path cocok dengan awalan request.path.
  • Kecocokan penuh: Pola path cocok dengan seluruh request.path.

Jika ada kecocokan penuh, aturan dalam blok dievaluasi. Jika ada kecocokan sebagian, aturan match bertingkat akan diuji untuk melihat apakah path bertingkat akan menghasilkan kecocokan penuh.

Aturan dalam setiap match penuh dievaluasi untuk menentukan apakah permintaan akan diizinkan atau tidak. Permintaan akan diizinkan jika aturan yang cocok memberikan akses. Permintaan akan ditolak jika tidak ada aturan yang cocok yang memberikan akses.

// Given request.path == /example/hello/nested/path the following
// declarations indicate whether they are a partial or complete match and
// the value of any variables visible within the scope.
service firebase.storage {
  // Partial match.
  match /example/{singleSegment} {   // `singleSegment` == 'hello'
    allow write;                     // Write rule not evaluated.
    // Complete match.
    match /nested/path {             // `singleSegment` visible in scope.
      allow read;                    // Read rule is evaluated.
    }
  }
  // Complete match.
  match /example/{multiSegment=**} { // `multiSegment` == /hello/nested/path
    allow read;                      // Read rule is evaluated.
  }
}

Seperti ditunjukkan pada contoh di atas, deklarasi path mendukung variabel berikut:

  • Karakter pengganti segmen tunggal: Variabel karakter pengganti dideklarasikan di jalur dengan mengapit variabel menggunakan kurung kurawal: {variable}. Variabel ini dapat diakses dalam pernyataan match sebagai string.
  • Karakter pengganti berulang: Karakter pengganti berulang, atau multisegmen, cocok dengan beberapa segmen jalur pada atau di bawah jalur. Karakter pengganti ini cocok dengan semua jalur di bawah lokasi yang ditentukan. Anda dapat mendeklarasikannya dengan menambahkan string =** di akhir variabel segmen: {variable=**}. Variabel ini dapat diakses dalam pernyataan match sebagai objek path.

Allow

Blok match berisi satu atau beberapa pernyataan allow. Pernyataan tersebut adalah aturan Anda yang sebenarnya. Anda dapat menerapkan aturan allow ke satu atau beberapa metode. Kondisi pada pernyataan allow harus bernilai benar agar Cloud Firestore atau Cloud Storage dapat memberikan izin untuk setiap permintaan yang masuk. Anda juga dapat menulis pernyataan allow tanpa kondisi, misalnya, allow read. Namun, jika pernyataan allow tidak menyertakan kondisi, pernyataan tersebut akan selalu mengizinkan permintaan untuk metode tersebut.

Jika ada aturan allow yang terpenuhi untuk metode tersebut, permintaan akan diizinkan. Selain itu, jika ada aturan yang lebih luas yang memberikan akses, Aturan akan memberikan akses dan mengabaikan aturan yang lebih terperinci yang mungkin membatasi akses.

Pertimbangkan contoh berikut, yang mengizinkan setiap pengguna untuk membaca atau menghapus file mereka sendiri. Aturan yang lebih terperinci hanya mengizinkan penulisan jika pengguna yang meminta penulisan adalah pemilik file dan file tersebut berformat PNG. Pengguna dapat menghapus semua file di subjalur — meskipun file tersebut tidak dalam format PNG — karena aturan sebelumnya mengizinkannya.

service firebase.storage {
  // Allow the requestor to read or delete any resource on a path under the
  // user directory.
  match /users/{userId}/{anyUserFile=**} {
    allow read, delete: if request.auth != null && request.auth.uid == userId;
  }

  // Allow the requestor to create or update their own images.
  // When 'request.method' == 'delete' this rule and the one matching
  // any path under the user directory would both match and the `delete`
  // would be permitted.

  match /users/{userId}/images/{imageId} {
    // Whether to permit the request depends on the logical OR of all
    // matched rules. This means that even if this rule did not explicitly
    // allow the 'delete' the earlier rule would have.
    allow write: if request.auth != null && request.auth.uid == userId && imageId.matches('*.png');
  }
}

Metode

Setiap pernyataan allow mencakup metode yang memberikan akses untuk permintaan masuk dari metode yang sama.

Metode Jenis permintaan
Metode praktis
read Semua jenis permintaan baca
write Semua jenis permintaan tulis
Metode standar
get Permintaan baca untuk dokumen atau file tunggal
list Permintaan baca untuk kueri dan koleksi
create Menulis dokumen atau file baru
update Menulis ke dokumen database yang sudah ada atau memperbarui metadata file
delete Menghapus data

Anda tidak dapat menimpa metode baca di blok match yang sama atau metode tulis yang bertentangan dalam deklarasi path yang sama.

Berikut contoh aturan yang akan gagal:

service bad.example {
  match /rules/with/overlapping/methods {
    // This rule allows reads to all authenticated users
    allow read: if request.auth != null;

    match another/subpath {
      // This secondary, more specific read rule causes an error
      allow get: if request.auth != null && request.auth.uid == "me";
      // Overlapping write methods in the same path cause an error as well
      allow write: if request.auth != null;
      allow create: if request.auth != null && request.auth.uid == "me";
    }
  }
}

Fungsi

Saat aturan keamanan menjadi makin kompleks, Anda dapat menggabungkan kumpulan kondisi ke dalam fungsi yang dapat digunakan kembali di semua kumpulan aturan. Aturan keamanan mendukung fungsi kustom. Sintaksis untuk fungsi kustom mirip dengan JavaScript, tetapi fungsi aturan keamanan ditulis dalam bahasa khusus domain yang memiliki beberapa batasan penting:

  • Fungsi hanya dapat berisi satu pernyataan return. Fungsi tidak boleh berisi logika lain apa pun. Misalnya, fungsi tidak dapat menjalankan loop atau memanggil layanan eksternal.
  • Fungsi dapat secara otomatis mengakses fungsi dan variabel dari cakupan tempat ditetapkannya. Misalnya, fungsi yang ditetapkan ke dalam cakupan service cloud.firestore memiliki akses ke variabel resource dan memiliki fungsi bawaan seperti get() dan exists().
  • Fungsi dapat memanggil fungsi lain tetapi tidak dapat secara berulang. Total kedalaman stack panggilan dibatasi hingga 20.
  • Dalam aturan versi v2, fungsi dapat menentukan variabel menggunakan kata kunci let. Fungsi dapat memiliki hingga 10 binding let, tetapi harus diakhiri dengan pernyataan return.

Fungsi ditetapkan dengan kata kunci function dan menerima nol argumen atau lebih. Misalnya, Anda dapat menggabungkan dua jenis kondisi yang digunakan dalam contoh di atas menjadi satu fungsi:

service cloud.firestore {
  match /databases/{database}/documents {
    // True if the user is signed in or the requested data is 'public'
    function signedInOrPublic() {
      return request.auth.uid != null || resource.data.visibility == 'public';
    }

    match /cities/{city} {
      allow read, write: if signedInOrPublic();
    }

    match /users/{user} {
      allow read, write: if signedInOrPublic();
    }
  }
}

Berikut adalah contoh yang menampilkan argumen fungsi dan tugas let. Pernyataan tugas let harus dipisahkan dengan tanda titik koma.

function isAuthorOrAdmin(userId, article) {
  let isAuthor = article.author == userId;
  let isAdmin = exists(/databases/$(database)/documents/admins/$(userId));
  return isAuthor || isAdmin;
}

Perhatikan cara tugas isAdmin menerapkan pencarian koleksi admin. Untuk evaluasi lambat tanpa mengharuskan pencarian yang tidak diperlukan, manfaatkan kepraktisan dari perbandingan && (AND) dan || (OR) untuk memanggil fungsi kedua hanya jika isAuthor ditampilkan dengan nilai true (benar) (untuk perbandingan &&) atau false (salah) (untuk perbandingan ||).

function isAdmin(userId) {
  return exists(/databases/$(database)/documents/admins/$(userId));
}
function isAuthorOrAdmin(userId, article) {
  let isAuthor = article.author == userId;
  // `||` is short-circuiting; isAdmin called only if isAuthor == false.
  return isAuthor || isAdmin(userId);
}

Dengan menggunakan fungsi, aturan keamanan akan lebih mudah dipertahankan seiring makin kompleksnya aturan.

Cloud Storage

Berikut elemen dasar aturan di Cloud Firestore dan Cloud Storage:

  • Deklarasi service: Mendeklarasikan pada produk Firebase apa aturan tersebut diterapkan.
  • Blok match: Menentukan jalur dalam database atau bucket penyimpanan tempat aturan tersebut diterapkan.
  • Pernyataan allow: Menentukan kondisi untuk memberikan akses, yang dibedakan berdasarkan metode. Metode yang didukung meliputi: get, list, create, update, delete, dan metode read dan write yang praktis.
  • Deklarasi function opsional: Memberikan kemampuan untuk mengombinasikan dan menggabungkan kondisi untuk digunakan pada beberapa aturan.

service berisi satu atau beberapa blok match dengan pernyataan allow yang menetapkan kondisi yang memberikan akses ke permintaan. Variabel request dan resource dapat diterapkan dalam kondisi aturan. Bahasa Aturan Keamanan Firebase juga mendukung deklarasi function.

Versi sintaksis

Pernyataan syntax menunjukkan versi bahasa Aturan Firebase yang digunakan untuk menulis sumber. Versi bahasa terbaru adalah v2.

rules_version = '2';
service cloud.firestore {
...
}

Jika tidak ada pernyataan rules_version yang diberikan, aturan Anda akan dievaluasi menggunakan mesin v1.

Service

Deklarasi service menentukan pada produk atau layanan Firebase apa aturan Anda diterapkan. Anda hanya dapat menyertakan satu deklarasi service per file sumber.

Cloud Firestore

service cloud.firestore {
 // Your 'match' blocks with their corresponding 'allow' statements and
 // optional 'function' declarations are contained here
}

Cloud Storage

service firebase.storage {
  // Your 'match' blocks with their corresponding 'allow' statements and
  // optional 'function' declarations are contained here
}

Aturan yang ditetapkan untuk Cloud Firestore dan Cloud Storage menggunakan Firebase CLI harus disimpan dalam file terpisah.

Match

Blok match mendeklarasikan pola path yang dicocokkan dengan jalur operasi yang diminta (request.path yang masuk). Isi match harus memiliki satu atau beberapa blok match bertingkat, pernyataan allow, atau deklarasi function. Jalur dalam blok match bertingkat bersifat relatif terhadap jalur dalam blok match induk.

Pola path adalah nama serupa direktori yang dapat mengandung variabel atau karakter pengganti. Dengan pola path, pencocokan segmen jalur tunggal dan segmen multi-jalur dapat dilakukan. Variabel apa pun yang terikat dengan path terlihat dalam cakupan match atau cakupan bertingkat tempat path dideklarasikan.

Kecocokan dengan pola path dapat bersifat sebagian atau penuh:

  • Kecocokan sebagian: Awalan pola path cocok dengan awalan request.path.
  • Kecocokan penuh: Pola path cocok dengan seluruh request.path.

Jika ada kecocokan penuh, aturan dalam blok dievaluasi. Jika ada kecocokan sebagian, aturan match bertingkat akan diuji untuk melihat apakah path bertingkat akan menghasilkan kecocokan penuh.

Aturan dalam setiap match penuh dievaluasi untuk menentukan apakah permintaan akan diizinkan atau tidak. Permintaan akan diizinkan jika aturan yang cocok memberikan akses. Permintaan akan ditolak jika tidak ada aturan yang cocok yang memberikan akses.

// Given request.path == /example/hello/nested/path the following
// declarations indicate whether they are a partial or complete match and
// the value of any variables visible within the scope.
service firebase.storage {
  // Partial match.
  match /example/{singleSegment} {   // `singleSegment` == 'hello'
    allow write;                     // Write rule not evaluated.
    // Complete match.
    match /nested/path {             // `singleSegment` visible in scope.
      allow read;                    // Read rule is evaluated.
    }
  }
  // Complete match.
  match /example/{multiSegment=**} { // `multiSegment` == /hello/nested/path
    allow read;                      // Read rule is evaluated.
  }
}

Seperti ditunjukkan pada contoh di atas, deklarasi path mendukung variabel berikut:

  • Karakter pengganti segmen tunggal: Variabel karakter pengganti dideklarasikan di jalur dengan mengapit variabel menggunakan kurung kurawal: {variable}. Variabel ini dapat diakses dalam pernyataan match sebagai string.
  • Karakter pengganti berulang: Karakter pengganti berulang, atau multisegmen, cocok dengan beberapa segmen jalur pada atau di bawah jalur. Karakter pengganti ini cocok dengan semua jalur di bawah lokasi yang ditentukan. Anda dapat mendeklarasikannya dengan menambahkan string =** di akhir variabel segmen: {variable=**}. Variabel ini dapat diakses dalam pernyataan match sebagai objek path.

Allow

Blok match berisi satu atau beberapa pernyataan allow. Pernyataan tersebut adalah aturan Anda yang sebenarnya. Anda dapat menerapkan aturan allow ke satu atau beberapa metode. Kondisi pada pernyataan allow harus bernilai benar agar Cloud Firestore atau Cloud Storage dapat memberikan izin untuk setiap permintaan yang masuk. Anda juga dapat menulis pernyataan allow tanpa kondisi, misalnya, allow read. Namun, jika pernyataan allow tidak menyertakan kondisi, pernyataan tersebut akan selalu mengizinkan permintaan untuk metode tersebut.

Jika ada aturan allow yang terpenuhi untuk metode tersebut, permintaan akan diizinkan. Selain itu, jika ada aturan yang lebih luas yang memberikan akses, Aturan akan memberikan akses dan mengabaikan aturan yang lebih terperinci yang mungkin membatasi akses.

Pertimbangkan contoh berikut, yang mengizinkan setiap pengguna untuk membaca atau menghapus file mereka sendiri. Aturan yang lebih terperinci hanya mengizinkan penulisan jika pengguna yang meminta penulisan adalah pemilik file dan file tersebut berformat PNG. Pengguna dapat menghapus semua file di subjalur — meskipun file tersebut tidak dalam format PNG — karena aturan sebelumnya mengizinkannya.

service firebase.storage {
  // Allow the requestor to read or delete any resource on a path under the
  // user directory.
  match /users/{userId}/{anyUserFile=**} {
    allow read, delete: if request.auth != null && request.auth.uid == userId;
  }

  // Allow the requestor to create or update their own images.
  // When 'request.method' == 'delete' this rule and the one matching
  // any path under the user directory would both match and the `delete`
  // would be permitted.

  match /users/{userId}/images/{imageId} {
    // Whether to permit the request depends on the logical OR of all
    // matched rules. This means that even if this rule did not explicitly
    // allow the 'delete' the earlier rule would have.
    allow write: if request.auth != null && request.auth.uid == userId && imageId.matches('*.png');
  }
}

Metode

Setiap pernyataan allow mencakup metode yang memberikan akses untuk permintaan masuk dari metode yang sama.

Metode Jenis permintaan
Metode praktis
read Semua jenis permintaan baca
write Semua jenis permintaan tulis
Metode standar
get Permintaan baca untuk dokumen atau file tunggal
list Permintaan baca untuk kueri dan koleksi
create Menulis dokumen atau file baru
update Menulis ke dokumen database yang sudah ada atau memperbarui metadata file
delete Menghapus data

Anda tidak dapat menimpa metode baca di blok match yang sama atau metode tulis yang bertentangan dalam deklarasi path yang sama.

Berikut contoh aturan yang akan gagal:

service bad.example {
  match /rules/with/overlapping/methods {
    // This rule allows reads to all authenticated users
    allow read: if request.auth != null;

    match another/subpath {
      // This secondary, more specific read rule causes an error
      allow get: if request.auth != null && request.auth.uid == "me";
      // Overlapping write methods in the same path cause an error as well
      allow write: if request.auth != null;
      allow create: if request.auth != null && request.auth.uid == "me";
    }
  }
}

Fungsi

Saat aturan keamanan menjadi makin kompleks, Anda dapat menggabungkan kumpulan kondisi ke dalam fungsi yang dapat digunakan kembali di semua kumpulan aturan. Aturan keamanan mendukung fungsi kustom. Sintaksis untuk fungsi kustom mirip dengan JavaScript, tetapi fungsi aturan keamanan ditulis dalam bahasa khusus domain yang memiliki beberapa batasan penting:

  • Fungsi hanya dapat berisi satu pernyataan return. Fungsi tidak boleh berisi logika lain apa pun. Misalnya, fungsi tidak dapat menjalankan loop atau memanggil layanan eksternal.
  • Fungsi dapat secara otomatis mengakses fungsi dan variabel dari cakupan tempat ditetapkannya. Misalnya, fungsi yang ditetapkan ke dalam cakupan service cloud.firestore memiliki akses ke variabel resource dan memiliki fungsi bawaan seperti get() dan exists().
  • Fungsi dapat memanggil fungsi lain tetapi tidak dapat secara berulang. Total kedalaman stack panggilan dibatasi hingga 20.
  • Dalam aturan versi v2, fungsi dapat menentukan variabel menggunakan kata kunci let. Fungsi dapat memiliki hingga 10 binding let, tetapi harus diakhiri dengan pernyataan return.

Fungsi ditetapkan dengan kata kunci function dan menerima nol argumen atau lebih. Misalnya, Anda dapat menggabungkan dua jenis kondisi yang digunakan dalam contoh di atas menjadi satu fungsi:

service cloud.firestore {
  match /databases/{database}/documents {
    // True if the user is signed in or the requested data is 'public'
    function signedInOrPublic() {
      return request.auth.uid != null || resource.data.visibility == 'public';
    }

    match /cities/{city} {
      allow read, write: if signedInOrPublic();
    }

    match /users/{user} {
      allow read, write: if signedInOrPublic();
    }
  }
}

Berikut adalah contoh yang menampilkan argumen fungsi dan tugas let. Pernyataan tugas let harus dipisahkan dengan tanda titik koma.

function isAuthorOrAdmin(userId, article) {
  let isAuthor = article.author == userId;
  let isAdmin = exists(/databases/$(database)/documents/admins/$(userId));
  return isAuthor || isAdmin;
}

Perhatikan cara tugas isAdmin menerapkan pencarian koleksi admin. Untuk evaluasi lambat tanpa mengharuskan pencarian yang tidak diperlukan, manfaatkan kepraktisan dari perbandingan && (AND) dan || (OR) untuk memanggil fungsi kedua hanya jika isAuthor ditampilkan dengan nilai true (benar) (untuk perbandingan &&) atau false (salah) (untuk perbandingan ||).

function isAdmin(userId) {
  return exists(/databases/$(database)/documents/admins/$(userId));
}
function isAuthorOrAdmin(userId, article) {
  let isAuthor = article.author == userId;
  // `||` is short-circuiting; isAdmin called only if isAuthor == false.
  return isAuthor || isAdmin(userId);
}

Dengan menggunakan fungsi, aturan keamanan akan lebih mudah dipertahankan seiring makin kompleksnya aturan.

Realtime Database

Sebagaimana diuraikan di atas, Aturan Realtime Database mencakup tiga elemen dasar: lokasi database sebagai cerminan struktur JSON database, jenis permintaan, dan kondisi yang memberikan akses.

Lokasi database

Struktur aturan Anda harus mengikuti struktur data yang telah disimpan di database. Misalnya, pada aplikasi chat dengan daftar pesan, data yang Anda miliki akan terlihat seperti ini:

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

Aturan yang dibuat harus mencerminkan struktur tersebut. Contoh:

  {
    "rules": {
      "messages": {
        "$message": {
          // only messages from the last ten minutes can be read
          ".read": "data.child('timestamp').val() > (now - 600000)",

          // new messages must have a string content and a number timestamp
          ".validate": "newData.hasChildren(['content', 'timestamp']) &&
                        newData.child('content').isString() &&
                        newData.child('timestamp').isNumber()"
        }
      }
    }
  }

Seperti dicontohkan di atas, 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 }
      }
    }
  }

Metode

Ada tiga jenis aturan pada Realtime Database. Dua dari jenis aturan ini — read dan write — berlaku pada metode permintaan masuk. Jenis aturan validate menerapkan struktur data dan memvalidasi format serta isi data. Aturan menjalankan aturan .validate setelah memverifikasi bahwa aturan .write telah memberikan akses.

Jenis Aturan
.read Menjelaskan apakah dan kapan data boleh dibaca oleh pengguna.
.write Menjelaskan apakah dan kapan data boleh ditulis.
.validate Menentukan tampilan nilai yang diformat dengan benar, apakah nilai memiliki atribut turunan, dan tipe data.

Secara default, jika tidak ada aturan yang mengizinkannya, akses di jalur akan ditolak.

Mem-build kondisi

Cloud Firestore

Kondisi adalah ekspresi boolean yang menentukan diizinkannya atau ditolaknya operasi tertentu. Variabel request dan resource memberikan konteks untuk kondisi tersebut.

Variabel request

Variabel request mencakup kolom dan informasi terkait berikut ini:

request.auth

Token Web JSON (JWT) yang berisi kredensial autentikasi dari Firebase Authentication. Token auth berisi kumpulan klaim standar dan klaim khusus yang dibuat melalui Firebase Authentication. Pelajari Aturan Keamanan Firebase dan Authentication lebih lanjut.

request.method

request.method dapat berupa metode standar atau metode kustom. Metode read dan write yang praktis juga dapat digunakan untuk menyederhanakan penulisan aturan yang berlaku untuk semua metode standar hanya baca atau hanya tulis.

request.params

request.params menyertakan semua data yang tidak secara spesifik terkait dengan request.resource yang mungkin berguna untuk proses evaluasi. Dalam praktiknya, peta ini harus kosong untuk semua metode standar, dan harus berisi data non-resource untuk metode kustom. Layanan harus berhati-hati agar tidak mengganti nama atau mengubah jenis kunci dan nilai apa pun yang ditampilkan sebagai params.

request.path

request.path adalah jalur untuk resource target. Jalur tersebut bersifat relatif terhadap layanan. Segmen jalur yang berisi karakter aman non-URL seperti / dienkode dengan URL.

Variabel resource

Variabel resource adalah nilai saat ini di dalam layanan yang ditampilkan sebagai peta key-value pair. Mereferensikan resource dalam suatu kondisi akan menghasilkan maksimal satu pembacaan nilai dari layanan. Pencarian ini akan diperhitungkan terhadap kuota terkait layanan untuk resource. Untuk permintaan get, resource hanya akan memperhitungkan kuota penolakan.

Operator dan prioritas operator

Gunakan tabel di bawah sebagai referensi untuk operator dan prioritasnya yang sesuai pada Aturan untuk Cloud Firestore dan Cloud Storage.

Ekspresi arbitrer tertentu a dan b, kolom f, dan indeks i.

Operator Deskripsi Asosiativitas
a[i] a() a.f Akses indeks, panggilan, kolom kiri ke kanan
!a -a Negasi unary kanan ke kiri
a/b a%b a*b Operator multiplikatif kiri ke kanan
a+b a-b Operator aditif kiri ke kanan
a>b a>=b a<=b Operator relasional kiri ke kanan
a in b Keberadaan dalam daftar atau peta kiri ke kanan
a is type Perbandingan jenis, dengan type dapat berupa bool, int, float, angka, string, daftar, peta, stempel waktu, durasi, jalur, atau latlng kiri ke kanan
a==b a!=b Operator perbandingan kiri ke kanan
a && b AND kondisional kiri ke kanan
a || b OR kondisional kiri ke kanan
a ? true_value : false_value Ekspresi ternary kiri ke kanan

Cloud Storage

Kondisi adalah ekspresi boolean yang menentukan diizinkannya atau ditolaknya operasi tertentu. Variabel request dan resource memberikan konteks untuk kondisi tersebut.

Variabel request

Variabel request mencakup kolom dan informasi terkait berikut ini:

request.auth

Token Web JSON (JWT) yang berisi kredensial autentikasi dari Firebase Authentication. Token auth berisi kumpulan klaim standar dan klaim khusus yang dibuat melalui Firebase Authentication. Pelajari Aturan Keamanan Firebase dan Authentication lebih lanjut.

request.method

request.method dapat berupa metode standar atau metode kustom. Metode read dan write yang praktis juga dapat digunakan untuk menyederhanakan penulisan aturan yang berlaku untuk semua metode standar hanya baca atau hanya tulis.

request.params

request.params menyertakan semua data yang tidak secara spesifik terkait dengan request.resource yang mungkin berguna untuk proses evaluasi. Dalam praktiknya, peta ini harus kosong untuk semua metode standar, dan harus berisi data non-resource untuk metode kustom. Layanan harus berhati-hati agar tidak mengganti nama atau mengubah jenis kunci dan nilai apa pun yang ditampilkan sebagai params.

request.path

request.path adalah jalur untuk resource target. Jalur tersebut bersifat relatif terhadap layanan. Segmen jalur yang berisi karakter aman non-URL seperti / dienkode dengan URL.

Variabel resource

Variabel resource adalah nilai saat ini di dalam layanan yang ditampilkan sebagai peta key-value pair. Mereferensikan resource dalam suatu kondisi akan menghasilkan maksimal satu pembacaan nilai dari layanan. Pencarian ini akan diperhitungkan terhadap kuota terkait layanan untuk resource. Untuk permintaan get, resource hanya akan memperhitungkan kuota penolakan.

Operator dan prioritas operator

Gunakan tabel di bawah sebagai referensi untuk operator dan prioritasnya yang sesuai pada Aturan untuk Cloud Firestore dan Cloud Storage.

Ekspresi arbitrer tertentu a dan b, kolom f, dan indeks i.

Operator Deskripsi Asosiativitas
a[i] a() a.f Akses indeks, panggilan, kolom kiri ke kanan
!a -a Negasi unary kanan ke kiri
a/b a%b a*b Operator multiplikatif kiri ke kanan
a+b a-b Operator aditif kiri ke kanan
a>b a>=b a<=b Operator relasional kiri ke kanan
a in b Keberadaan dalam daftar atau peta kiri ke kanan
a is type Perbandingan jenis, dengan type dapat berupa bool, int, float, angka, string, daftar, peta, stempel waktu, durasi, jalur, atau latlng kiri ke kanan
a==b a!=b Operator perbandingan kiri ke kanan
a && b AND kondisional kiri ke kanan
a || b OR kondisional kiri ke kanan
a ? true_value : false_value Ekspresi ternary kiri ke kanan

Realtime Database

Kondisi adalah ekspresi boolean yang menentukan diizinkannya atau ditolaknya operasi tertentu. Anda dapat menentukan kondisi tersebut pada Aturan Realtime Database dengan cara berikut.

Variabel yang telah ditetapkan

Ada sejumlah variabel bermanfaat yang telah ditetapkan, yang dapat diakses di dalam definisi aturan. Berikut adalah ringkasan dari setiap variabel tersebut:

Variabel yang Telah Ditetapkan
now Waktu saat ini dalam satuan milidetik sejak epoch Linux. Variabel ini bekerja dengan baik terutama untuk memvalidasi stempel waktu yang dibuat dengan firebase.database.ServerValue.TIMESTAMP SDK.
root RuleDataSnapshot yang mewakili keadaan jalur root di database Firebase sebelum percobaan pengoperasian.
newData RuleDataSnapshot yang mewakili keadaan data setelah percobaan pengoperasian. Variabel ini mencakup data baru yang sedang ditulis dan data yang sudah ada.
data RuleDataSnapshot yang mewakili keadaan data sebelum percobaan pengoperasian.
$ variables Jalur karakter pengganti yang digunakan untuk mewakili ID dan kunci turunan dinamis.
auth Mewakili payload token pengguna yang telah diautentikasi.

Variabel ini bisa digunakan di mana saja dalam aturan Anda. Misalnya, aturan keamanan di bawah memastikan bahwa data yang ditulis ke node /foo/ harus berupa string sepanjang kurang dari 100 karakter:

{
  "rules": {
    "foo": {
      // /foo is readable by the world
      ".read": true,

      // /foo is writable by the world
      ".write": true,

      // data written to /foo must be a string less than 100 characters
      ".validate": "newData.isString() && newData.val().length < 100"
    }
  }
}

Aturan berbasis data

Setiap data pada database Anda dapat digunakan dalam aturan Anda. Dengan menggunakan variabel root, data, dan newData yang telah ditetapkan, Anda dapat mengakses setiap jalur sebagaimana adanya sebelum atau setelah peristiwa tulis.

Pertimbangkan contoh ini, yang memungkinkan operasi tulis selama nilai node /allow_writes/ adalah true, node induk tidak memiliki flag readOnly yang ditetapkan, dan terdapat turunan bernama foo dalam data yang baru ditulis:

".write": "root.child('allow_writes').val() === true &&
          !data.parent().child('readOnly').exists() &&
          newData.child('foo').exists()"

Aturan berbasis kueri

Meskipun tidak dapat menggunakan aturan sebagai filter, Anda dapat membatasi akses ke subkumpulan data dengan menggunakan parameter kueri dalam aturan. Gunakan ekspresi query. dalam aturan Anda untuk memberikan akses baca atau tulis berdasarkan parameter kueri.

Misalnya, aturan berbasis kueri berikut menggunakan aturan keamanan berbasis pengguna dan aturan berbasis kueri untuk membatasi akses ke data yang ada di koleksi baskets hanya bagi keranjang belanja milik pengguna aktif:

"baskets": {
  ".read": "auth.uid !== null &&
            query.orderByChild === 'owner' &&
            query.equalTo === auth.uid" // restrict basket access to owner of basket
}

Kueri berikut, yang mencakup parameter kueri dalam aturan, akan berhasil diterapkan:

db.ref("baskets").orderByChild("owner")
                 .equalTo(auth.currentUser.uid)
                 .on("value", cb)                 // Would succeed

Namun, kueri yang tidak menyertakan parameter dalam aturan akan gagal dengan error PermissionDenied:

db.ref("baskets").on("value", cb)                 // Would fail with PermissionDenied

Anda juga dapat menggunakan aturan berbasis kueri untuk membatasi jumlah data yang didownload klien melalui operasi baca.

Misalnya, aturan berikut membatasi akses baca hanya untuk 1.000 hasil kueri pertama, yang diurutkan berdasarkan prioritas:

messages: {
  ".read": "query.orderByKey &&
            query.limitToFirst <= 1000"
}

// Example queries:

db.ref("messages").on("value", cb)                // Would fail with PermissionDenied

db.ref("messages").limitToFirst(1000)
                  .on("value", cb)                // Would succeed (default order by key)

Ekspresi query. berikut tersedia di Aturan Keamanan Realtime Database.

Ekspresi aturan berbasis kueri
Ekspresi Jenis Deskripsi
query.orderByKey
query.orderByPriority
query.orderByValue
boolean Benar untuk kueri yang diurutkan berdasarkan kunci, prioritas, atau nilai. Salah untuk kueri yang tidak diurutkan.
query.orderByChild string
null
Gunakan string untuk mewakili jalur relatif ke node turunan. Misalnya, query.orderByChild === "address/zip". Jika kueri tidak diurutkan berdasarkan node turunan, nilai ini adalah null.
query.startAt
query.endAt
query.equalTo
string
number
boolean
null
Mengambil ikatan kueri yang mengeksekusi, atau menampilkan null jika tidak ada ikatan yang ditetapkan.
query.limitToFirst
query.limitToLast
number
null
Mengambil batasan kueri pelaksana, atau menampilkan null jika tidak ada batasan yang ditetapkan.

Operator

Aturan Realtime Database mendukung sejumlah operator yang dapat Anda gunakan untuk menggabungkan variabel dalam pernyataan kondisi. Lihat daftar lengkap operator dalam dokumentasi referensi.

Membuat kondisi

Kondisi sebenarnya akan bervariasi berdasarkan akses yang ingin Anda berikan. Aturan sengaja menawarkan tingkat fleksibilitas yang sangat besar, sehingga aturan aplikasi Anda pada akhirnya bisa sesederhana atau serumit yang Anda inginkan.

Untuk mengetahui panduan cara membuat Aturan siap produksi yang sederhana, lihat Aturan Keamanan Dasar.