Quy tắc bảo mật cơ bản

Firebase Security Rules cho phép bạn kiểm soát quyền truy cập vào dữ liệu đã lưu trữ của bạn. Quy tắc linh hoạt nghĩa là bạn có thể tạo các quy tắc phù hợp với bất kỳ thứ gì, từ tất cả các lượt ghi cho đến toàn bộ cơ sở dữ liệu để thao tác trên một tài liệu cụ thể.

Hướng dẫn này mô tả một số trường hợp sử dụng cơ bản hơn mà bạn có thể muốn triển khai khi thiết lập ứng dụng và bảo vệ dữ liệu của mình. Tuy nhiên, trước khi bắt đầu viết quy tắc, bạn nên tìm hiểu thêm về ngôn ngữ mà các quy tắc đó được viết và hành vi của các quy tắc đó.

Để truy cập và cập nhật quy tắc, hãy làm theo các bước nêu trong Quản lý và triển khai Firebase Security Rules.

Quy tắc mặc định: Chế độ khoá

Khi bạn tạo một cơ sở dữ liệu hoặc thực thể lưu trữ trong bảng điều khiển Firebase, bạn chọn có cho phép Firebase Security Rules hạn chế quyền truy cập vào dữ liệu của bạn hay không (Chế độ khoá) hoặc cho phép mọi người truy cập (Chế độ thử nghiệm). Trong Cloud FirestoreRealtime Database, các quy tắc mặc định cho Chế độ khoá từ chối quyền truy cập cho tất cả người dùng. Trong Cloud Storage, chỉ những người dùng đã xác thực mới có thể truy cập vào bộ chứa lưu trữ.

Cloud Firestore

service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if false;
    }
  }
}

Realtime Database

{
  "rules": {
    ".read": false,
    ".write": false
  }
}

Cloud Storage

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

Quy tắc về môi trường phát triển

Trong khi làm việc trên ứng dụng, bạn có thể muốn có quyền truy cập tương đối mở hoặc không bị hạn chế vào dữ liệu của mình. Hãy nhớ cập nhật Rules của bạn trước bạn triển khai ứng dụng chính thức. Ngoài ra, hãy nhớ rằng nếu bạn triển khai ứng dụng, ứng dụng có thể truy cập công khai — ngay cả khi bạn chưa phát hành ứng dụng.

Hãy nhớ rằng Firebase cho phép khách hàng truy cập trực tiếp vào dữ liệu của bạn và Firebase Security Rules là biện pháp bảo vệ duy nhất để chặn hành vi truy cập của người dùng độc hại. Định nghĩa các quy tắc tách biệt với logic sản phẩm có một số ưu điểm: khách hàng thì không chịu trách nhiệm thực thi bảo mật, việc triển khai bị lỗi sẽ không ảnh hưởng đến dữ liệu của bạn và quan trọng nhất là bạn không phải dựa vào máy chủ trung gian nhằm bảo vệ dữ liệu khỏi bất cứ thứ gì trên thế giới.

Tất cả người dùng đã xác thực

Mặc dù bạn không nên để bất kỳ người dùng nào đăng nhập, thì bạn nên thiết lập quyền truy cập cho bất kỳ người dùng đã xác thực nào trong khi bạn đang phát triển ứng dụng của mình.

Cloud Firestore

service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if request.auth != null;
    }
  }
}

Realtime Database

{
  "rules": {
    ".read": "auth.uid !== null",
    ".write": "auth.uid !== null"
  }
}

Cloud Storage

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

Quy tắc sẵn sàng phát hành công khai

Khi bạn chuẩn bị triển khai ứng dụng, hãy đảm bảo dữ liệu của bạn được bảo vệ và rằng quyền truy cập được cấp thích hợp cho người dùng của bạn. Tận dụng Authentication để thiết lập quyền truy cập dựa trên người dùng và đọc trực tiếp từ cơ sở dữ liệu để thiết lập quyền truy cập dựa trên dữ liệu.

Hãy cân nhắc viết các quy tắc khi bạn xây dựng cấu trúc dữ liệu, vì đây là cách bạn thiết lập quy tắc của mình sẽ tác động đến cách bạn hạn chế quyền truy cập vào dữ liệu ở đường dẫn.

Quyền truy cập chỉ dành cho chủ sở hữu nội dung

Các quy tắc này chỉ hạn chế quyền truy cập với chủ sở hữu đã xác thực của nội dung. Chiến lược phát hành đĩa đơn mà chỉ một người dùng có thể đọc và ghi dữ liệu này, còn đường dẫn dữ liệu sẽ chứa mã nhận dạng của người dùng.

Khi quy tắc này hoạt động: Quy tắc này sẽ hoạt động tốt nếu dữ liệu bị tách biệt bởi người dùng – nếu Người dùng duy nhất cần truy cập vào dữ liệu chính là người dùng đã tạo .

Khi quy tắc này không hoạt động: Bộ quy tắc này không hoạt động khi có nhiều người dùng cần ghi hoặc đọc cùng một dữ liệu — người dùng sẽ ghi đè dữ liệu hoặc không thể để truy cập vào dữ liệu mà họ đã tạo.

Cách thiết lập quy tắc này: Hãy tạo một quy tắc xác nhận người dùng yêu cầu quyền truy cập đọc hoặc ghi dữ liệu là người dùng sở hữu dữ liệu đó.

Cloud Firestore

service cloud.firestore {
  match /databases/{database}/documents {
    // Allow only authenticated content owners access
    match /some_collection/{userId}/{documents=**} {
      allow read, write: if request.auth != null && request.auth.uid == userId
    }
  }
}

Realtime Database

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

Cloud Storage

// Grants a user access to a node matching their user ID
service firebase.storage {
  match /b/{bucket}/o {
    // Files look like: "user/<UID>/path/to/file.txt"
    match /user/{userId}/{allPaths=**} {
      allow read, write: if request.auth != null && request.auth.uid == userId;
    }
  }
}

Quyền truy cập riêng tư và công khai hỗn hợp

Quy tắc này cho phép bất cứ ai đọc tập dữ liệu, nhưng hạn chế khả năng tạo hoặc sửa đổi dữ liệu theo đường dẫn nhất định đến chủ sở hữu nội dung đã được xác thực.

Khi quy tắc này hoạt động: Quy tắc này sẽ phù hợp với các ứng dụng yêu cầu công khai các phần tử có thể đọc được, nhưng cần hạn chế quyền chỉnh sửa đối với các phần tử đó chủ sở hữu. Ví dụ: ứng dụng trò chuyện hoặc blog.

Khi quy tắc này không hoạt động: Giống như quy tắc chỉ dành cho chủ sở hữu nội dung, bộ quy tắc này không hoạt động khi nhiều người dùng cần chỉnh sửa cùng một dữ liệu. Cuối cùng, người dùng sẽ ghi đè dữ liệu của nhau.

Cách thiết lập quy tắc này: Hãy tạo một quy tắc bật quyền đọc cho tất cả người dùng (hoặc tất cả người dùng đã xác thực) và xác nhận người dùng ghi dữ liệu là chủ sở hữu.

Cloud Firestore

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 create: if request.auth.uid == request.resource.data.author_uid;
      allow update, delete: if request.auth.uid == resource.data.author_uid;
    }
  }
}

Realtime Database

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

Cloud Storage

service firebase.storage {
  match /b/{bucket}/o {
    // Files look like: "user/<UID>/path/to/file.txt"
    match /user/{userId}/{allPaths=**} {
      allow read;
      allow write: if request.auth.uid == userId;
    }
  }
}

Quyền truy cập dựa trên thuộc tính và dựa trên vai trò

Để quy tắc này hoạt động, bạn phải xác định và chỉ định các thuộc tính cho người dùng trong . Firebase Security Rules kiểm tra yêu cầu này dựa trên dữ liệu từ cơ sở dữ liệu hoặc tệp để xác nhận hoặc từ chối cấp quyền truy cập.

Khi quy tắc này hoạt động: Nếu bạn đang chỉ định vai trò cho người dùng, quy tắc này sẽ dễ dàng giới hạn quyền truy cập theo vai trò hoặc nhóm người dùng cụ thể. Ví dụ: nếu đang lưu trữ điểm, bạn có thể chỉ định các cấp truy cập khác nhau cho nhóm "học viên" (chỉ đọc nội dung của họ), nhóm "giáo viên" (đọc và ghi trong môn học của họ) và nhóm "hiệu trưởng" (đọc tất cả nội dung).

Khi quy tắc này không hoạt động: Trong Realtime DatabaseCloud Storage, các quy tắc của bạn không thể tận dụng phương thức get()Cloud Firestore quy tắc có thể kết hợp. Do đó, bạn phải xây dựng cấu trúc cơ sở dữ liệu hoặc siêu dữ liệu tệp để phản ánh các thuộc tính bạn đang sử dụng trong quy tắc của mình.

Cách thiết lập quy tắc này: Trong Cloud Firestore, hãy thêm một trường vào mã tài liệu mà bạn có thể đọc, sau đó cấu trúc quy tắc để đọc quy tắc đó. và cấp quyền truy cập theo điều kiện. Trong Realtime Database, hãy tạo một đường dẫn dữ liệu xác định người dùng của ứng dụng và cấp cho họ một vai trò trong nút con.

Bạn cũng có thể thiết lập thông báo xác nhận quyền sở hữu tuỳ chỉnh trong Authentication rồi truy xuất thông tin đó từ Biến auth.token trong Firebase Security Rules bất kỳ.

Thuộc tính và vai trò do dữ liệu xác định

Các quy tắc này chỉ áp dụng trong Cloud FirestoreRealtime Database.

Cloud Firestore

Hãy nhớ rằng bất cứ khi nào quy tắc của bạn bao gồm một thao tác đọc, chẳng hạn như các quy tắc bên dưới, bạn sẽ bị tính phí cho một thao tác đọc trong Cloud Firestore.

service cloud.firestore {
  match /databases/{database}/documents {
    // For attribute-based access control, Check a boolean `admin` attribute
    allow write: if get(/databases/$(database)/documents/users/$(request.auth.uid)).data.admin == true;
    allow read: true;

    // Alterntatively, for role-based access, assign specific roles to users
    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"
   }
  }
}

Realtime Database

{
  "rules": {
    "some_path": {
      "${subpath}": {
        //
        ".write": "root.child('users').child(auth.uid).child('role').val() === 'admin'",
        ".read": true
      }
    }
  }
}

Thuộc tính và vai trò của thông báo xác nhận quyền sở hữu tuỳ chỉnh

Để triển khai các quy tắc này, hãy thiết lập thông báo xác nhận quyền sở hữu tuỳ chỉnh trong Firebase Authentication rồi tận dụng các thông báo xác nhận quyền sở hữu trong quy tắc của bạn.

Cloud Firestore

service cloud.firestore {
  match /databases/{database}/documents {
    // For attribute-based access control, check for an admin claim
    allow write: if request.auth.token.admin == true;
    allow read: true;

    // Alterntatively, for role-based access, assign specific roles to users
    match /some_collection/{document} {
     allow read: if request.auth.token.reader == "true";
     allow write: if request.auth.token.writer == "true";
   }
  }
}

Realtime Database

{
  "rules": {
    "some_path": {
      "$uid": {
        // Create a custom claim for each role or group
        // you want to leverage
        ".write": "auth.uid !== null && auth.token.writer === true",
        ".read": "auth.uid !== null && auth.token.reader === true"
      }
    }
  }
}

Cloud Storage

service firebase.storage {
  // Allow reads if the group ID in your token matches the file metadata's `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;
  }
}

Thuộc tính nhà cho thuê

Để triển khai các quy tắc này, hãy thiết lập cơ chế đa người dùng trong Google Cloud Identity Platform (GCIP) rồi tận dụng đối tượng thuê trong các quy tắc của mình. Các ví dụ sau đây cho phép ghi từ người dùng trong một đối tượng thuê cụ thể, ví dụ: tenant2-m6tyz

Cloud Firestore

service cloud.firestore {
  match /databases/{database}/documents {
    // For tenant-based access control, check for a tenantID
    allow write: if request.auth.token.firebase.tenant == 'tenant2-m6tyz';
    allow read: true;
  }
}

Realtime Database

{
  "rules": {
    "some_path": {
      "$uid": {
        // Only allow reads and writes if user belongs to a specific tenant
        ".write": "auth.uid !== null && auth.token.firebase.tenant === 'tenant2-m6tyz'",
        ".read": "auth.uid !== null
      }
    }
  }
}

Cloud Storage

service firebase.storage {
  // Only allow reads and writes if user belongs to a specific tenant
  match /files/{tenantId}/{fileName} {
    allow read: if request.auth != null;
    allow write: if request.auth.token.firebase.tenant == tenantId;
  }
}