Firebase Security Rules ช่วยให้คุณควบคุมการเข้าถึงข้อมูลที่จัดเก็บไว้ได้ รูปแบบกฎที่ยืดหยุ่นช่วยให้คุณสร้างกฎที่ตรงกับทุกสิ่งได้ ตั้งแต่การเขียนทั้งหมดไปยังทั้งฐานข้อมูลไปจนถึงการดำเนินการในเอกสารที่เฉพาะเจาะจง
คู่มือนี้จะอธิบาย Use Case พื้นฐานบางอย่างที่คุณอาจต้องการนำไปใช้ขณะตั้งค่าแอปและปกป้องข้อมูลของคุณ อย่างไรก็ตาม ก่อนเริ่มเขียนกฎ คุณอาจต้องดูข้อมูลเพิ่มเติมเกี่ยวกับภาษาที่ใช้เขียนกฎและลักษณะการทํางานของกฎ
หากต้องการเข้าถึงและอัปเดตกฎ ให้ทําตามขั้นตอนที่ระบุไว้ในจัดการและติดตั้งใช้งาน Firebase Security Rules
กฎเริ่มต้น: โหมดล็อก
เมื่อสร้างอินสแตนซ์ฐานข้อมูลหรือพื้นที่เก็บข้อมูลในคอนโซล Firebase คุณสามารถเลือกได้ว่าจะให้ Firebase Security Rules จำกัดการเข้าถึงข้อมูล (โหมดล็อก) หรืออนุญาตให้ทุกคนเข้าถึง (โหมดทดสอบ) ใน Cloud Firestore และ Realtime Database กฎเริ่มต้นสำหรับโหมดที่ล็อกจะปฏิเสธการเข้าถึงสำหรับผู้ใช้ทั้งหมด ใน Cloud Storage เฉพาะผู้ใช้ที่ได้รับการตรวจสอบสิทธิ์เท่านั้นที่จะเข้าถึงที่เก็บข้อมูลได้
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;
}
}
}
กฎของสภาพแวดล้อมการพัฒนาซอฟต์แวร์
ขณะพัฒนาแอป คุณอาจต้องการการเข้าถึงข้อมูลแบบเปิดหรือแบบไม่จำกัด อย่าลืมอัปเดต Rules ก่อนทำให้แอปใช้งานได้จริง นอกจากนี้ โปรดทราบว่าหากทําให้การเผยแพร่แอปของคุณเข้าถึงได้แบบสาธารณะ แม้ว่าคุณจะยังไม่ได้เปิดตัวแอปก็ตาม
โปรดทราบว่า Firebase อนุญาตให้ไคลเอ็นต์เข้าถึงข้อมูลของคุณโดยตรง และ Firebase Security Rules เป็นมาตรการป้องกันเพียงอย่างเดียวที่บล็อกการเข้าถึงของผู้ใช้ที่เป็นอันตราย การกําหนดกฎแยกจากตรรกะผลิตภัณฑ์มีข้อดีหลายประการ ได้แก่ ลูกค้าไม่ต้องรับผิดชอบในการบังคับใช้ความปลอดภัย การติดตั้งใช้งานที่มีข้อบกพร่องจะไม่ทําให้ข้อมูลของคุณตกอยู่ในความเสี่ยง และที่สำคัญที่สุดคือคุณไม่ต้องอาศัยเซิร์ฟเวอร์สื่อกลางเพื่อปกป้องข้อมูลจากโลกภายนอก
ผู้ใช้ที่ได้รับการตรวจสอบสิทธิ์ทั้งหมด
แม้ว่าเราจะไม่แนะนำให้ผู้ใช้ที่ลงชื่อเข้าใช้สามารถเข้าถึงข้อมูลของคุณได้ แต่การกำหนดสิทธิ์เข้าถึงให้กับผู้ใช้ที่ผ่านการตรวจสอบสิทธิ์ขณะที่คุณพัฒนาแอปก็อาจมีประโยชน์
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;
}
}
}
กฎที่พร้อมใช้งานจริง
เมื่อเตรียมที่จะทําให้แอปใช้งานได้ ให้ตรวจสอบว่าข้อมูลได้รับการปกป้องและผู้ใช้ได้รับสิทธิ์เข้าถึงอย่างเหมาะสม ใช้ประโยชน์จาก Authentication เพื่อตั้งค่าการเข้าถึงตามผู้ใช้และอ่านจากฐานข้อมูลโดยตรงเพื่อตั้งค่าการเข้าถึงตามข้อมูล
ลองเขียนกฎขณะจัดโครงสร้างข้อมูล เนื่องจากวิธีตั้งค่ากฎจะส่งผลต่อวิธีจํากัดการเข้าถึงข้อมูลในเส้นทางต่างๆ
สิทธิ์เข้าถึงสำหรับเจ้าของเนื้อหาเท่านั้น
กฎเหล่านี้จำกัดการเข้าถึงไว้สำหรับเจ้าของเนื้อหาที่ตรวจสอบสิทธิ์แล้วเท่านั้น ข้อมูลดังกล่าวจะมีเพียงผู้ใช้รายเดียวที่อ่านและเขียนได้ และเส้นทางข้อมูลจะมีรหัสของผู้ใช้
กรณีที่กฎนี้ใช้งานได้: กฎนี้ใช้งานได้ดีหากมีการแยกข้อมูลตามผู้ใช้ กล่าวคือ ผู้ใช้เพียงคนเดียวที่ต้องเข้าถึงข้อมูลได้คือผู้ใช้ที่สร้างข้อมูลนั้น
กรณีที่กฎนี้ใช้งานไม่ได้: ชุดกฎนี้จะไม่ทำงานเมื่อผู้ใช้หลายคนต้องเขียนหรืออ่านข้อมูลเดียวกัน ผู้ใช้จะเขียนทับข้อมูลหรือเข้าถึงข้อมูลที่ตนสร้างขึ้นไม่ได้
วิธีตั้งค่ากฎนี้: สร้างกฎที่ยืนยันว่าผู้ใช้ที่ขอสิทธิ์เข้าถึงเพื่ออ่านหรือเขียนข้อมูลคือผู้ใช้ที่เป็นเจ้าของข้อมูลนั้น
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;
}
}
}
การเข้าถึงแบบผสมระหว่างสาธารณะและส่วนตัว
กฎนี้อนุญาตให้ทุกคนอ่านชุดข้อมูลได้ แต่จะจำกัดความสามารถในการสร้างหรือแก้ไขข้อมูลในเส้นทางที่ระบุไว้สำหรับเจ้าของเนื้อหาที่ตรวจสอบสิทธิ์เท่านั้น
กรณีที่กฎนี้ใช้งานได้: กฎนี้เหมาะกับแอปที่ต้องมีองค์ประกอบที่อ่านได้แบบสาธารณะ แต่ต้องจำกัดการเข้าถึงการแก้ไขไว้สำหรับเจ้าขององค์ประกอบเหล่านั้น เช่น แอปแชทหรือบล็อก
กรณีที่กฎนี้ใช้ไม่ได้: เช่นเดียวกับกฎสำหรับเจ้าของเนื้อหาเท่านั้น ชุดกฎนี้จะใช้ไม่ได้เมื่อผู้ใช้หลายคนต้องแก้ไขข้อมูลเดียวกัน ผู้ใช้จะเขียนทับข้อมูลของกันและกันในท้ายที่สุด
วิธีตั้งค่ากฎนี้: สร้างกฎที่เปิดใช้สิทธิ์การอ่านสําหรับผู้ใช้ทุกคน (หรือผู้ใช้ที่ตรวจสอบสิทธิ์แล้วทั้งหมด) และยืนยันว่าผู้ใช้ที่เขียนข้อมูลเป็นเจ้าของ
Cloud Firestore
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;
}
}
}
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;
}
}
}
สิทธิ์เข้าถึงตามแอตทริบิวต์และตามบทบาท
คุณต้องกําหนดและมอบหมายแอตทริบิวต์ให้กับผู้ใช้ในข้อมูลเพื่อให้กฎเหล่านี้ทํางาน Firebase Security Rules ตรวจสอบคำขอเทียบกับข้อมูลจากข้อมูลเมตาของฐานข้อมูลหรือไฟล์เพื่อยืนยันหรือปฏิเสธการเข้าถึง
กรณีที่กฎนี้ทำงาน: หากคุณกําลังมอบหมายบทบาทให้กับผู้ใช้ กฎนี้จะช่วยให้คุณจํากัดการเข้าถึงตามบทบาทหรือกลุ่มผู้ใช้ที่เฉพาะเจาะจงได้ง่ายๆ เช่น หากจัดเก็บคะแนน คุณสามารถกำหนดระดับการเข้าถึงที่แตกต่างกันให้กับกลุ่ม "นักเรียน" (อ่านเนื้อหาเท่านั้น) กลุ่ม "ครู" (อ่านและเขียนในวิชา) และกลุ่ม "ครูใหญ่" (อ่านเนื้อหาทั้งหมด)
กรณีที่กฎนี้ใช้ไม่ได้: ใน Realtime Database และ Cloud Storage กฎของคุณจะใช้เมธอด get()
ที่กฎ Cloud Firestore นำมาใช้ได้ไม่ได้
คุณจึงต้องจัดโครงสร้างฐานข้อมูลหรือข้อมูลเมตาของไฟล์ให้สอดคล้องกับแอตทริบิวต์ที่คุณใช้ในกฎ
วิธีตั้งค่ากฎนี้: ใน Cloud Firestore ให้ใส่ช่องในเอกสารของผู้ใช้ที่คุณอ่านได้ จากนั้นจัดโครงสร้างกฎให้อ่านช่องนั้นและมอบสิทธิ์เข้าถึงแบบมีเงื่อนไข ใน Realtime Database ให้สร้างเส้นทางข้อมูลที่กําหนดผู้ใช้ของแอปและมอบหมายบทบาทให้ผู้ใช้เหล่านั้นในโหนดย่อย
นอกจากนี้ คุณยังตั้งค่าการอ้างสิทธิ์ที่กําหนดเองใน Authentication แล้วดึงข้อมูลดังกล่าวจากตัวแปร auth.token
ใน Firebase Security Rules ใดก็ได้
แอตทริบิวต์และบทบาทที่กําหนดโดยข้อมูล
กฎเหล่านี้ใช้ได้ใน Cloud Firestore และ Realtime Database เท่านั้น
Cloud Firestore
โปรดทราบว่าทุกครั้งที่กฎมีการอ่าน เช่น กฎด้านล่าง ระบบจะเรียกเก็บเงินจากคุณสำหรับการดำเนินการอ่านใน 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
}
}
}
}
แอตทริบิวต์และบทบาทการอ้างสิทธิ์ที่กำหนดเอง
หากต้องการใช้กฎเหล่านี้ ให้ตั้งค่าการอ้างสิทธิ์ที่กําหนดเองใน Firebase Authentication แล้วใช้ประโยชน์จากการอ้างสิทธิ์ในกฎ
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;
}
}
แอตทริบิวต์ขององค์กร
หากต้องการใช้กฎเหล่านี้ ให้ตั้งค่าการรองรับผู้ใช้หลายรายใน Google Cloud Identity Platform (GCIP) แล้วใช้ประโยชน์จากข้อมูลเทนนต์ในกฎ ตัวอย่างต่อไปนี้อนุญาตให้เขียนจากผู้ใช้ในเทนนต์ที่เฉพาะเจาะจง เช่น 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;
}
}