กฎความปลอดภัยพื้นฐาน

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