Menghindari aturan yang tidak aman

Gunakan panduan ini untuk memahami kerentanan umum dalam konfigurasi Firebase Security Rules, meninjau dan mengamankan aturan Anda sendiri dengan lebih baik, dan menguji perubahan yang Anda buat sebelum di-deploy.

Jika Anda menerima peringatan bahwa data Anda tidak diamankan dengan baik, tinjau error yang umum terjadi ini dan perbarui aturan yang rentan.

Mengakses Firebase Security Rules

Untuk melihat Rules yang sudah ada, gunakan Firebase CLI atau Firebase console. Pastikan Anda mengedit aturan menggunakan metode yang sama secara konsisten, agar tidak ada pembaruan yang tumpang tindih secara tidak sengaja. Jika tidak yakin bahwa aturan yang Anda tentukan secara lokal mencerminkan pembaruan terkini, Firebase console selalu menunjukkan versi Firebase Security Rules yang paling baru di-deploy.

Untuk mengakses aturan Anda dari Firebase console, pilih project, lalu buka Realtime Database, Cloud Firestore, atau Storage. Klik Aturan setelah Anda berada di database atau bucket penyimpanan yang tepat.

Untuk mengakses aturan dari Firebase CLI, buka file aturan yang tercantum pada file firebase.json Anda.

Memahami Firebase Security Rules

Firebase Security Rules melindungi data Anda dari pengguna yang berbahaya. Saat membuat instance database atau bucket Cloud Storage di konsol Firebase, Anda dapat memilih untuk menolak akses ke semua pengguna (Mode terkunci) atau memberikan akses ke semua pengguna (Mode pengujian). Meskipun Anda mungkin menginginkan konfigurasi yang lebih terbuka selama pengembangan, pastikan Anda mengonfigurasi aturan dan mengamankan data Anda dengan benar sebelum men-deploy aplikasi.

Saat Anda mengembangkan aplikasi dan menguji berbagai konfigurasi untuk aturan Anda, gunakan salah satu emulator Firebase lokal untuk menjalankan aplikasi Anda di lingkungan pengembangan lokal.

Skenario umum dengan aturan yang tidak aman

Rules yang mungkin telah Anda siapkan secara default atau saat Anda mulai mengembangkan aplikasi harus ditinjau dan diperbarui sebelum Anda men-deploy aplikasi. Pastikan Anda mengamankan data pengguna dengan benar dengan menghindari kesalahan umum berikut.

Akses terbuka

Ketika menyiapkan project Firebase, Anda mungkin telah menetapkan aturan yang mengizinkan akses terbuka selama pengembangan. Anda mungkin berpikir bahwa Anda adalah satu-satunya orang yang menggunakan aplikasi, tetapi jika Anda telah men-deploy-nya, aplikasi tersebut akan tersedia di internet. Jika Anda tidak mengautentikasi pengguna dan mengonfigurasi aturan keamanan, maka siapa saja yang dapat menebak project ID Anda dapat mencuri, memodifikasi, atau menghapus data.

Tidak disarankan: Akses baca dan tulis untuk semua pengguna.
// Allow read/write access to all users under any conditions
// Warning: **NEVER** use this ruleset in production; it allows
// anyone to overwrite your entire database.

service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if true;
    }
  }
}
{
  // Allow read/write access to all users under any conditions
  // Warning: **NEVER** use this ruleset in production; it allows
  // anyone to overwrite your entire database.

  "rules": {
    ".read": true,
    ".write": true
  }
}
    
// Anyone can read or write to the bucket, even non-users of your app.
// Because it is shared with App Engine, this will also make
// files uploaded using App Engine public.
// Warning: This rule makes every file in your Cloud Storage bucket accessible to any user.
// Apply caution before using it in production, since it means anyone
// can overwrite all your files.

service firebase.storage {
  match /b/{bucket}/o {
    match /{allPaths=**} {
      allow read, write;
    }
  }
}
    
Solusi: Aturan yang membatasi akses baca dan tulis.

Buat aturan yang sesuai untuk hierarki data Anda. Salah satu solusi yang umum untuk ketidakamanan ini adalah keamanan berbasis pengguna dengan Firebase Authentication. Pelajari lebih lanjut cara mengautentikasi pengguna dengan aturan.

service cloud.firestore {
  match /databases/{database}/documents {
    // Allow only authenticated content owners access
    match /some_collection/{document} {
      // Allow reads and deletion if the current user owns the existing document
      allow read, delete: if request.auth.uid == resource.data.author_uid;
      // Allow creation if the current user owns the new document
      allow create: if request.auth.uid == request.resource.data.author_uid;
      // Allow updates by the owner, and prevent change of ownership
      allow update: if request.auth.uid == request.resource.data.author_uid
                    && request.auth.uid == resource.data.author_uid;

    }
  }
}
  
service cloud.firestore {
  match /databases/{database}/documents {
    // Allow public read access, but only content owners can write
    match /some_collection/{document} {
      // Allow public reads
      allow read: if true
      // Allow creation if the current user owns the new document
      allow create: if request.auth.uid == request.resource.data.author_uid;
      // Allow updates by the owner, and prevent change of ownership
      allow update: if request.auth.uid == request.resource.data.author_uid
                    && request.auth.uid == resource.data.author_uid;
      // Allow deletion if the current user owns the existing document
      allow delete: if request.auth.uid == resource.data.author_uid;
    }
  }
}
  
{
  "rules": {
    "some_path": {
      "$uid": {
        // Allow only authenticated content owners access to their data
        ".read": "auth !== null && auth.uid === $uid",
        ".write": "auth !== null && auth.uid === $uid"
      }
    }
  }
}
    
{
  // Allow anyone to read data, but only authenticated content owners can
  // make changes to their data

  "rules": {
    "some_path/$uid": {
      ".read": true,
      // or ".read": "auth.uid !== null" for only authenticated users
      ".write": "auth.uid === $uid"
    }
  }
}
    
// Grants a user access to a node matching their user ID
service firebase.storage {
  match /b/{bucket}/o {
    // Files look like: "user/<UID>/file.txt"
    match /user/{userId}/{fileName} {
      allow read, write: if request.auth.uid == userId;
    }
  }
}
service firebase.storage {
  match /b/{bucket}/o {
    // Files look like: "user/<UID>/file.txt"
    match /user/{userId}/{fileName} {
      allow read;
      allow write: if request.auth.uid == userId;
    }
  }
}
  

Akses untuk setiap pengguna yang diautentikasi

Terkadang, Rules memastikan apakah pengguna sudah login, tetapi tidak membatasi akses lebih lanjut berdasarkan autentikasi tersebut. Jika salah satu aturan Anda menyertakan auth != null, konfirmasikan bahwa Anda ingin setiap pengguna yang login memiliki akses ke data.

Tidak direkomendasikan: Setiap pengguna yang login memiliki akses baca dan tulis ke seluruh database Anda.
service cloud.firestore {
  match /databases/{database}/documents {
    match /some_collection/{document} {
      allow read, write: if request.auth.uid != null;
    }
  }
}
{
  "rules": {
    ".read": "auth.uid !== null",
    ".write": "auth.uid !== null"
  }
}
// Only authenticated users can read or write to the bucket
service firebase.storage {
  match /b/{bucket}/o {
    match /{allPaths=**} {
      allow read, write: if request.auth != null;
    }
  }
}
Solusi: Persempit akses menggunakan kondisi keamanan.

Saat memeriksa autentikasi, Anda juga dapat menggunakan salah satu properti autentikasi untuk membatasi akses lebih lanjut bagi pengguna tertentu ke set data tertentu. Pelajari lebih lanjut berbagai properti autentikasi.

service cloud.firestore {
  match /databases/{database}/documents {
    // Assign roles to all users and refine access based on user roles
    match /some_collection/{document} {
     allow read: if get(/databases/$(database)/documents/users/$(request.auth.uid)).data.role == "Reader"
     allow write: if get(/databases/$(database)/documents/users/$(request.auth.uid)).data.role == "Writer"

     // Note: Checking for roles in your database using `get` (as in the code
     // above) or `exists` carry standard charges for read operations.
    }
  }
}
// Give each user in your database a particular attribute
// and set it to true/false
// Then, use that attribute to grant access to subsets of data
// For example, an "administrator" attribute set
// to "true" grants write access to data

service cloud.firestore {
  match /databases/{database}/documents {
    match /some_collection/{document} {
      allow write: if get(/databases/$(database)/documents/users/$(request.auth.uid)).data.admin == true;
      allow read: true;
    }
  }
}
  
service cloud.firestore {
  match /databases/{database}/documents {
    // Allow public read access, but only content owners can write
    match /some_collection/{document} {
      allow read: if true
      allow write: if request.auth.uid == request.resource.data.author_uid
    }
  }
}
  
{
  "rules": {
    "some_path": {
      "$uid": {
        // Allow only authenticated content owners access to their data
        ".read": "auth.uid === $uid",
        ".write": "auth.uid === $uid"
      }
    }
  }
}
    
{
  "rules": {
    "some_path/$uid": {
      ".write": "auth.uid === $uid",
      // Create a "public" subpath in your dataset
      "public": {
        ".read": true
        // or ".read": "auth.uid !== null"
      },
      // Create a "private" subpath in your dataset
      "private": {
        ".read": "auth.uid === $uid"
      }
    }
  }
}
    
{
  // Allow anyone to read data, but only authenticated content owners can
  // make changes to their data

  "rules": {
    "some_path/$uid": {
      ".read": true,
      // or ".read": "auth.uid !== null" for only authenticated users
      ".write": "auth.uid === $uid"
    }
  }
}
    
// Allow reads if the group ID in your token matches the file metadata `owner` property
// Allow writes if the group ID is in the user's custom token
match /files/{groupId}/{fileName} {
  allow read: if resource.metadata.owner == request.auth.token.groupId;
  allow write: if request.auth.token.groupId == groupId;
}
// Grants a user access to a node matching their user ID
service firebase.storage {
  match /b/{bucket}/o {
    // Files look like: "user/<UID>/file.txt"
    match /user/{userId}/{fileName} {
      allow read, write: if request.auth.uid == userId;
    }
  }
}
service firebase.storage {
  match /b/{bucket}/o {
    // Files look like: "user/<UID>/file.txt"
    match /user/{userId}/{fileName} {
      allow read;
      allow write: if request.auth.uid == userId;
    }
  }
}
  

(Realtime Database) Aturan yang diturunkan dengan tidak semestinya

Realtime Database Security Rules bersifat menurun, yaitu aturan di jalur induk yang lebih dangkal akan mengganti aturan di node turunan yang lebih dalam. Saat Anda menulis aturan di node turunan, ingat bahwa node tersebut hanya dapat memberikan hak istimewa tambahan. Anda tidak dapat memperbaiki atau mencabut akses ke data di jalur yang lebih dalam di database Anda.

Tidak direkomendasikan: Memperbaiki aturan di jalur turunan
{
  "rules": {
     "foo": {
        // allows read to /foo/*
        ".read": "data.child('baz').val() === true",
        "bar": {
          /* ignored, since read was allowed already */
          ".read": false
        }
     }
  }
}
Solusi: Tuliskan aturan di jalur induk yang luas dan berikan lebih banyak hak istimewa di jalur turunan. Jika kebutuhan akses data Anda memerlukan lebih banyak perincian, pertahankan aturan Anda secara terperinci. Pelajari lebih lanjut Realtime Database Security Rules berurutan dalam Sintaksis utama Realtime Database Security Rules.

Akses tertutup

Saat Anda mengembangkan aplikasi, pendekatan umum lainnya adalah menjaga data Anda tetap terkunci. Biasanya, ini berarti Anda menutup akses baca dan tulis untuk semua pengguna, seperti berikut ini:

// Deny read/write access to all users under any conditions
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if false;
    }
  }
}
{
  "rules": {
    ".read": false,
    ".write": false
  }
}
    
// Access to files through Cloud Storage is completely disallowed.
// Files may still be accessible through App Engine or Google Cloud Storage APIs.

service firebase.storage {
  match /b/{bucket}/o {
    match /{allPaths=**} {
      allow read, write: if false;
    }
  }
}

Firebase Admin SDK dan Cloud Functions masih dapat mengakses database Anda. Gunakan aturan ini saat Anda bermaksud menggunakan Cloud Firestore atau Realtime Database sebagai backend khusus server bersama dengan Firebase Admin SDK. Meskipun aman, Anda harus menguji apakah klien aplikasi Anda dapat mengambil data dengan benar.

Pelajari lebih lanjut Cloud Firestore Security Rules dan cara kerjanya di bagian Memulai Cloud Firestore Security Rules.

Uji Cloud Firestore Security Rules Anda

Untuk memeriksa perilaku aplikasi dan memverifikasi konfigurasi Cloud Firestore Security Rules, gunakan Firebase Emulator. Gunakan emulator Cloud Firestore untuk menjalankan dan mengotomatiskan pengujian unit di lingkungan lokal sebelum Anda men-deploy perubahan.

Untuk memvalidasi Firebase Security Rules dengan cepat di konsol Firebase, gunakan Simulator Aturan Firebase.