Các quy tắc bảo mật cơ bản

Quy tắc bảo mật Firebase cho phép bạn kiểm soát quyền truy cập vào dữ liệu được lưu trữ của mình. Cú pháp quy tắc linh hoạt có nghĩa là bạn có thể tạo các quy tắc khớp với mọi thứ, từ tất cả các thao tác ghi vào toàn bộ cơ sở dữ liệu đến các 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 các quy tắc, bạn có thể muốn tìm hiểu thêm về ngôn ngữ viết các quy tắc đó và hành vi của chúng .

Để truy cập và cập nhật các quy tắc của bạn, hãy làm theo các bước được nêu trong Quản lý và triển khai Quy tắc bảo mật Firebase .

Quy tắc mặc định: Chế độ khóa

Khi tạo cơ sở dữ liệu hoặc phiên bản lưu trữ trong bảng điều khiển Firebase, bạn chọn xem Quy tắc bảo mật Firebase hạn chế quyền truy cập vào dữ liệu của bạn ( Chế độ khóa ) hay cho phép bất kỳ ai truy cập ( Chế độ kiểm tra ). Trong Cloud Firestore và Cơ sở dữ liệu thời gian thực, các quy tắc mặc định cho chế độ Đã khóa từ chối quyền truy cập của tất cả người dùng. Trong Cloud Storage, chỉ những người dùng được xác thực mới có thể truy cập vào nhóm lưu trữ.

Cửa hàng đám mây

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

Cơ sở dữ liệu thời gian thực

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

Lưu trữ đám mây

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

Quy định về môi trường phát triển

Trong khi làm việc trên ứng dụng của mình, bạn có thể muốn có quyền truy cập tương đối cởi mở hoặc không bị cản trở vào dữ liệu của mình. Chỉ cần đảm bảo cập nhật Quy tắc của bạn trước khi triển khai ứng dụng của mình vào sản xuất. Ngoài ra, hãy nhớ rằng nếu bạn triển khai ứng dụng của mình thì ứng dụng đó sẽ có thể truy cập công khai — ngay cả khi bạn chưa khởi chạy ứ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à Quy tắc bảo mật Firebase là biện pháp bảo vệ duy nhất chặn quyền truy cập đối với người dùng độc hại. Việc xác định các quy tắc riêng biệt với logic sản phẩm có một số lợi thế: khách hàng không chịu trách nhiệm thực thi bảo mật, việc triển khai có lỗi sẽ không làm tổn hại đến dữ liệu của bạn và quan trọng nhất là bạn không dựa vào máy chủ trung gian để bảo vệ dữ liệu khỏi thế giới.

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

Mặc dù chúng tôi khuyên bạn không nên để bất kỳ người dùng nào đã đăng nhập có thể truy cập dữ liệu của mình, nhưng việc đặt quyền truy cập cho bất kỳ người dùng được xác thực nào trong khi bạn đang phát triển ứng dụng của mình có thể hữu ích.

Cửa hàng đám mây

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

Cơ sở dữ liệu thời gian thực

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

Lưu trữ đám mây

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

Quy tắc sẵn sàng sản xuất

Khi bạn chuẩn bị triển khai ứng dụng của mình, hãy đảm bảo dữ liệu của bạn được bảo vệ và quyền truy cập đó được cấp hợp lý cho người dùng của bạn. Tận dụng Xác thực để 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 của bạn để thiết lập quyền truy cập dựa trên dữ liệu.

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

Quyền truy cập chỉ của chủ sở hữu nội dung

Các quy tắc này chỉ hạn chế quyền truy cập đối với chủ sở hữu nội dung đã được xác thực. Dữ liệu chỉ có thể đọc và ghi được bởi một người dùng và đường dẫn dữ liệu chứa ID của người dùng.

Khi quy tắc này hoạt động: Quy tắc này hoạt động tốt nếu dữ liệu được người dùng lưu trữ — 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 dữ liệu.

Khi quy tắc này không hoạt động: Bộ quy tắc này không hoạt động khi 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 dữ liệu họ đã tạo.

Để thiết lập quy tắc này: Tạo 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 đó.

Cửa hàng đám mây

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

Cơ sở dữ liệu thời gian thực

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

Lưu trữ đám mây

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

Truy cập hỗn hợp công cộng và riêng tư

Quy tắc này cho phép mọi người đọc tập dữ liệu nhưng chỉ hạn chế khả năng tạo hoặc sửa đổi dữ liệu tại một đường dẫn nhất định đối với 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 hoạt động tốt đối với các ứng dụng yêu cầu các thành phần có thể đọc công khai nhưng cần hạn chế quyền truy cập chỉnh sửa đối với chủ sở hữu của các thành phần đó. Ví dụ: một ứ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ỉ 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. Người dùng cuối cùng sẽ ghi đè lên dữ liệu của nhau.

Để thiết lập quy tắc này: Tạo quy tắc cho phép truy cập đọc cho tất cả người dùng (hoặc tất cả người dùng được xác thực) và xác nhận người dùng ghi dữ liệu là chủ sở hữu.

Cửa hàng đám mây

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

Cơ sở dữ liệu thời gian thực

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

Lưu trữ đám mây

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

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

Để các quy tắc này hoạt động, bạn phải xác định và gán thuộc tính cho người dùng trong dữ liệu của mình. Quy tắc bảo mật của Firebase kiểm tra yêu cầu dựa trên dữ liệu từ cơ sở dữ liệu hoặc siêu dữ liệu của tệp của bạn để xác nhận hoặc từ chối 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 giúp bạn dễ dàng giới hạn quyền truy cập dựa trên vai trò hoặc nhóm người dùng cụ thể. Ví dụ: nếu bạn đ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 sinh" (chỉ đọc nội dung của họ), nhóm "giáo viên" (đọc và viết trong môn học của họ) và nhóm "hiệu trưởng" (đọc toàn bộ nội dung).

Khi quy tắc này không hoạt động: Trong Cơ sở dữ liệu thời gian thực và Lưu trữ đám mây, quy tắc của bạn không thể tận dụng phương thức get() mà quy tắc Cloud Firestore có thể kết hợp. Do đó, bạn phải 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.

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

Bạn cũng có thể thiết lập xác nhận quyền sở hữu tùy chỉnh trong Xác thực , sau đó truy xuất thông tin đó từ biến auth.token trong bất kỳ Quy tắc bảo mật Firebase nào.

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

Các quy tắc này chỉ hoạt động trong Cloud Firestore và Cơ sở dữ liệu thời gian thực.

Cửa hàng đám mây

Hãy nhớ rằng bất cứ khi nào quy tắc của bạn bao gồm thao tác đọc, như các quy tắc bên dưới, bạn sẽ bị tính phí cho 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"
   }
  }
}

Cơ sở dữ liệu thời gian thực

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

Thuộc tính và vai trò xác nhận quyền sở hữu tùy chỉnh

Để triển khai các quy tắc này, hãy thiết lập xác nhận quyền sở hữu tùy chỉnh trong Xác thực Firebase và sau đó tận dụng các xác nhận quyền sở hữu trong quy tắc của bạn.

Cửa hàng đám mây

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

Cơ sở dữ liệu thời gian thực

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

Lưu trữ đám mây

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 thuê nhà

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

Cửa hàng đám mây

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

Cơ sở dữ liệu thời gian thực

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

Lưu trữ đám mây

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