หลีกเลี่ยงกฎที่ไม่ปลอดภัย

ใช้คู่มือนี้เพื่อทำความเข้าใจช่องโหว่ที่พบได้ทั่วไปในการกำหนดค่า Firebase Security Rules ตรวจสอบและเพิ่มความปลอดภัยให้กับกฎของคุณเอง และทดสอบการเปลี่ยนแปลงก่อนนำไปใช้งาน

หากคุณได้รับการแจ้งเตือนว่าข้อมูลของคุณไม่ปลอดภัยอย่างเหมาะสม ให้ตรวจสอบข้อผิดพลาดที่พบได้ทั่วไปเหล่านี้และอัปเดตกฎที่มีช่องโหว่

เข้าถึง Firebase Security Rules

หากต้องการดู Rules ที่มีอยู่ ให้ใช้ Firebase CLI หรือคอนโซล Firebase ตรวจสอบว่าคุณแก้ไขกฎโดยใช้วิธีการเดียวกันอย่างสม่ำเสมอเพื่อหลีกเลี่ยงการเขียนทับการอัปเดตโดยไม่ได้ตั้งใจ หากไม่แน่ใจว่ากฎที่กําหนดในเครื่องเป็นอัปเดตล่าสุดหรือไม่ คอนโซล Firebase จะแสดง Firebase Security Rules เวอร์ชันที่ติดตั้งใช้งานล่าสุดเสมอ

หากต้องการเข้าถึงกฎจากคอนโซล Firebase ให้เลือกโปรเจ็กต์ แล้วไปที่ Realtime Database, Cloud Firestore หรือพื้นที่เก็บข้อมูล คลิกกฎเมื่อคุณอยู่ในฐานข้อมูลหรือที่เก็บข้อมูลถังที่ถูกต้อง

หากต้องการเข้าถึงกฎจาก Firebase CLI ให้ไปที่ไฟล์กฎที่ระบุไว้ในไฟล์ firebase.json

ทำความเข้าใจ Firebase Security Rules

Firebase Security Rules ปกป้องข้อมูลของคุณจากผู้ใช้ที่เป็นอันตราย เมื่อสร้างอินสแตนซ์ฐานข้อมูลหรือที่เก็บข้อมูล Cloud Storage ในคอนโซล Firebase คุณจะเลือกปฏิเสธการเข้าถึงสำหรับผู้ใช้ทั้งหมด (โหมดล็อก) หรือให้สิทธิ์เข้าถึงแก่ผู้ใช้ทั้งหมด (โหมดทดสอบ) ก็ได้ แม้ว่าคุณอาจต้องการการกำหนดค่าที่เปิดกว้างมากขึ้นในระหว่างการพัฒนา แต่อย่าลืมใช้เวลาในการกำหนดค่ากฎและรักษาความปลอดภัยให้ข้อมูลอย่างเหมาะสมก่อนนำแอปของคุณไปใช้งาน

ขณะพัฒนาแอปและทดสอบการกําหนดค่าต่างๆ สําหรับกฎ ให้ใช้โปรแกรมจําลอง Firebase ในพื้นที่ตัวใดตัวหนึ่งเพื่อเรียกใช้แอปในสภาพแวดล้อมการพัฒนาในเครื่อง

สถานการณ์ที่พบบ่อยซึ่งมีกฎที่ไม่ปลอดภัย

Rules ที่คุณอาจตั้งค่าไว้โดยค่าเริ่มต้นหรือเมื่อคุณเริ่มพัฒนาแอปในตอนแรกควรได้รับการตรวจสอบและอัปเดตก่อนที่จะนำแอปของคุณไปใช้งานจริง โปรดตรวจสอบว่าคุณรักษาความปลอดภัยให้ข้อมูลของผู้ใช้อย่างเหมาะสมโดยหลีกเลี่ยงข้อผิดพลาดที่พบได้ทั่วไปต่อไปนี้

การเข้าถึงแบบเปิด

เมื่อตั้งค่าโปรเจ็กต์ Firebase คุณอาจตั้งกฎให้อนุญาตการเข้าถึงแบบเปิดในระหว่างการพัฒนา คุณอาจคิดว่าคุณเป็นผู้ใช้แอปเพียงคนเดียว แต่หากมีการใช้งานแอปดังกล่าว แสดงว่าแอปนั้นพร้อมให้บริการบนอินเทอร์เน็ต หากคุณไม่ได้ตรวจสอบสิทธิ์ผู้ใช้และกำหนดค่ากฎการรักษาความปลอดภัย ทุกคนที่คาดเดารหัสโปรเจ็กต์ของคุณได้จะขโมย แก้ไข หรือลบข้อมูลได้

ไม่แนะนำ: สิทธิ์อ่านและเขียนสำหรับผู้ใช้ทุกคน
// 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;
    }
  }
}
    
วิธีแก้ไข: กฎที่จำกัดสิทธิ์การอ่านและเขียน

สร้างกฎที่เหมาะกับลําดับชั้นของข้อมูล หนึ่งในวิธีแก้ปัญหาที่พบบ่อยสำหรับความไม่ปลอดภัยนี้ก็คือการรักษาความปลอดภัยตามผู้ใช้ด้วย Firebase Authentication ดูข้อมูลเพิ่มเติมเกี่ยวกับการตรวจสอบสิทธิ์ผู้ใช้ด้วยกฎ

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

สิทธิ์เข้าถึงสำหรับผู้ใช้ที่ได้รับการตรวจสอบสิทธิ์

บางครั้ง Rules จะตรวจสอบว่าผู้ใช้เข้าสู่ระบบแล้ว แต่จะไม่จำกัดการเข้าถึงเพิ่มเติมตามการตรวจสอบสิทธิ์นั้น หากกฎข้อใดข้อหนึ่งมี auth != null ให้ยืนยันว่าคุณต้องการให้ผู้ใช้ที่เข้าสู่ระบบมีสิทธิ์เข้าถึงข้อมูล

ไม่แนะนํา: ผู้ใช้ที่ลงชื่อเข้าสู่ระบบทุกคนจะมีสิทธิ์อ่านและเขียนฐานข้อมูลทั้งหมด
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;
    }
  }
}
วิธีแก้ปัญหา: จำกัดการเข้าถึงโดยใช้เงื่อนไขด้านความปลอดภัย

เมื่อตรวจสอบการตรวจสอบสิทธิ์ คุณอาจต้องใช้พร็อพเพอร์ตี้การตรวจสอบสิทธิ์อย่างใดอย่างหนึ่งเพื่อจํากัดการเข้าถึงผู้ใช้ที่เจาะจงสําหรับชุดข้อมูลหนึ่งๆ เพิ่มเติมด้วย ดูข้อมูลเพิ่มเติมเกี่ยวกับพร็อพเพอร์ตี้การตรวจสอบสิทธิ์ต่างๆ

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) กฎที่รับค่าเดิมอย่างไม่ถูกต้อง

Realtime Database Security Rules มีผลแบบซ้อนทับ โดยกฎในเส้นทางหลักที่อยู่ตื้นกว่าจะลบล้างกฎที่โหนดย่อยที่อยู่ลึกกว่า เมื่อเขียนกฎที่โหนดย่อย โปรดทราบว่ากฎดังกล่าวจะให้สิทธิ์เพิ่มเติมได้เท่านั้น คุณจะปรับแต่งหรือเพิกถอนสิทธิ์เข้าถึงข้อมูลในเส้นทางที่ลึกขึ้นในฐานข้อมูลไม่ได้

ไม่แนะนํา: การปรับแต่งกฎที่เส้นทางย่อย
{
  "rules": {
     "foo": {
        // allows read to /foo/*
        ".read": "data.child('baz').val() === true",
        "bar": {
          /* ignored, since read was allowed already */
          ".read": false
        }
     }
  }
}
วิธีแก้ปัญหา: เขียนกฎที่เส้นทางหลักให้ครอบคลุม และมอบสิทธิ์ที่เฉพาะเจาะจงมากขึ้นที่เส้นทางย่อย หากความต้องการในการเข้าถึงข้อมูลมีความซับซ้อนมากขึ้น ให้เขียนกฎให้ละเอียด ดูข้อมูลเพิ่มเติมเกี่ยวกับ Realtime Database Security Rules แบบเรียงซ้อนในไวยากรณ์หลักของ Realtime Database Security Rules

การเข้าถึงถูกปิด

อีกแนวทางที่พบบ่อยระหว่างการพัฒนาแอปคือการล็อกข้อมูลไว้ โดยปกติแล้ว การดำเนินการนี้หมายความว่าคุณได้ปิดการเข้าถึงระดับอ่านและเขียนสำหรับผู้ใช้ทั้งหมด ดังนี้

// 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 และ Cloud Functions จะยังคงเข้าถึงฐานข้อมูลได้ ใช้กฎเหล่านี้เมื่อคุณต้องการใช้ Cloud Firestore หรือ Realtime Database เป็นแบ็กเอนด์แบบเซิร์ฟเวอร์เท่านั้นร่วมกับ Firebase Admin SDK แม้ว่าจะปลอดภัยแล้ว แต่คุณควรทดสอบว่าไคลเอ็นต์ของแอปสามารถดึงข้อมูลได้อย่างถูกต้อง

ดูข้อมูลเพิ่มเติมเกี่ยวกับ Cloud Firestore Security Rules และวิธีการทํางานในหัวข้อเริ่มต้นใช้งาน Cloud Firestore Security Rules

ทดสอบ Cloud Firestore Security Rules

หากต้องการตรวจสอบลักษณะการทํางานของแอปและยืนยันการกําหนดค่า Cloud Firestore Security Rules ให้ใช้ Firebase Emulator ใช้Cloud Firestoreโปรแกรมจําลองเพื่อเรียกใช้และทําการทดสอบหน่วยแบบอัตโนมัติในสภาพแวดล้อมภายในก่อนที่จะทําการเปลี่ยนแปลง

หากต้องการตรวจสอบ Firebase Security Rules ในคอนโซล Firebase อย่างรวดเร็ว ให้ใช้เครื่องจำลองกฎ Firebase