วิธีการทำงานของกฎความปลอดภัย

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

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

เลือกผลิตภัณฑ์เพื่อดูข้อมูลเพิ่มเติมเกี่ยวกับกฎของผลิตภัณฑ์

Cloud Firestore

โครงสร้างพื้นฐาน

Firebase Security Rules ใน Cloud Firestore และ Cloud Storage ใช้โครงสร้างและไวยากรณ์ต่อไปนี้

service <<name>> {
  // Match the resource path.
  match <<path>> {
    // Allow the request if the following conditions are true.
    allow <<methods>> : if <<condition>>
  }
}

แนวคิดหลักต่อไปนี้เป็นสิ่งสำคัญที่ควรทำความเข้าใจขณะสร้างกฎ

  • คำขอ: เมธอดที่เรียกใช้ในคำสั่ง allow ซึ่งเป็น วิธีการที่คุณอนุญาตให้เรียกใช้ วิธีการมาตรฐาน ได้แก่ get, list, create, update และ delete เมธอดอำนวยความสะดวก read และ write ช่วยให้เข้าถึงการอ่านและการเขียนในเส้นทางฐานข้อมูลหรือที่เก็บข้อมูลที่ระบุได้อย่างกว้างขวาง
  • เส้นทาง: ฐานข้อมูลหรือตำแหน่งที่จัดเก็บซึ่งแสดงเป็นเส้นทาง URI
  • กฎ: คำสั่ง allow ซึ่งมีเงื่อนไขที่อนุญาตคำขอหากประเมินค่าเป็นจริง

กฎความปลอดภัยเวอร์ชัน 2

ตั้งแต่เดือนพฤษภาคม 2019 เป็นต้นไป Firebaseกฎความปลอดภัยเวอร์ชัน 2 พร้อมใช้งานแล้ว การเปลี่ยนแปลงกฎเวอร์ชันที่ 2 จะเปลี่ยนลักษณะการทำงานของอักขระไวด์การ์ด แบบเรียกซ้ำ {name=**} คุณต้องใช้เวอร์ชัน 2 หากวางแผนที่จะใช้การค้นหากลุ่มคอลเล็กชัน คุณต้องเลือกใช้ เวอร์ชัน 2 โดยทำrules_version = '2';บรรทัดแรกในกฎความปลอดภัย ของคุณดังนี้

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {

เส้นทางที่ตรงกัน

คำสั่งจับคู่ทั้งหมดควรชี้ไปยังเอกสาร ไม่ใช่คอลเล็กชัน คำสั่ง match สามารถชี้ไปยังเอกสารที่เฉพาะเจาะจงได้ เช่น match /cities/SF หรือใช้ไวลด์การ์ด เพื่อชี้ไปยังเอกสารใดก็ได้ในเส้นทางที่ระบุ เช่น match /cities/{city}

ในตัวอย่างนี้ คำสั่ง match ใช้ไวยากรณ์ไวลด์การ์ด {city} ซึ่งหมายความว่ากฎจะมีผลกับเอกสารใดก็ตามในคอลเล็กชัน cities เช่น /cities/SF หรือ /cities/NYC เมื่อมีการประเมินallowนิพจน์ในคำสั่งที่ตรงกัน ตัวแปร city จะเปลี่ยนเป็นชื่อเอกสารเมือง เช่น SF หรือ NYC

การจับคู่คอลเล็กชันย่อย

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

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

service cloud.firestore {
  match /databases/{database}/documents {
    match /cities/{city} {
      allow read, write: if <condition>;

      // Explicitly define rules for the 'landmarks' subcollection
      match /landmarks/{landmark} {
        allow read, write: if <condition>;
      }
    }
  }
}

เมื่อซ้อนคำสั่ง match เส้นทางของคำสั่ง match ด้านในจะสัมพันธ์กับเส้นทางของคำสั่ง match ด้านนอกเสมอ ดังนั้นชุดกฎต่อไปนี้ จึงมีความหมายเหมือนกัน

service cloud.firestore {
  match /databases/{database}/documents {
    match /cities/{city} {
      match /landmarks/{landmark} {
        allow read, write: if <condition>;
      }
    }
  }
}
service cloud.firestore {
  match /databases/{database}/documents {
    match /cities/{city}/landmarks/{landmark} {
      allow read, write: if <condition>;
    }
  }
}

ข้อความที่ตรงกันซึ่งซ้อนทับกัน

เอกสารอาจตรงกับmatchคำสั่งมากกว่า 1 รายการ ในกรณีที่นิพจน์ allow หลายรายการตรงกับคำขอ ระบบจะอนุญาตให้เข้าถึง หากเงื่อนไขใดเงื่อนไขหนึ่งเป็น true

service cloud.firestore {
  match /databases/{database}/documents {
    // Matches any document in the 'cities' collection.
    match /cities/{city} {
      allow read, write: if false;
    }

    // Matches any document in the 'cities' collection.
    match /cities/{document} {
      allow read, write: if true;
    }
  }
}

ในตัวอย่างนี้ ระบบจะอนุญาตการอ่านและการเขียนทั้งหมดไปยังคอลเล็กชัน cities เนื่องจากกฎที่ 2 เป็น true เสมอ แม้ว่ากฎแรกจะเป็น false เสมอ

ไวลด์การ์ดแบบเรียกซ้ำ

หากต้องการให้กฎมีผลกับลำดับชั้นที่ลึกโดยพลการ ให้ใช้ไวยากรณ์ไวลด์การ์ดแบบเรียกซ้ำ {name=**}:

service cloud.firestore {
  match /databases/{database}/documents {
    // Matches any document in the cities collection as well as any document
    // in a subcollection.
    match /cities/{document=**} {
      allow read, write: if <condition>;
    }
  }
}

เมื่อใช้ไวยากรณ์ไวลด์การ์ดแบบเรียกซ้ำ ตัวแปรไวลด์การ์ดจะมีส่วนเส้นทางที่ตรงกันทั้งหมด แม้ว่าเอกสารจะอยู่ในคอลเล็กชันย่อยที่ซ้อนกันลึกก็ตาม ตัวอย่างเช่น กฎที่แสดงจะตรงกับเอกสารที่อยู่ใน /cities/SF/landmarks/coit_tower และค่าของตัวแปร document จะเป็น SF/landmarks/coit_tower

อย่างไรก็ตาม โปรดทราบว่าลักษณะการทำงานของไวลด์การ์ดแบบเรียกซ้ำจะขึ้นอยู่กับเวอร์ชันของกฎ

เวอร์ชัน 1

กฎความปลอดภัยจะใช้เวอร์ชัน 1 โดยค่าเริ่มต้น ในเวอร์ชัน 1 ไวลด์การ์ดแบบเรียกซ้ำ จะตรงกับรายการเส้นทางอย่างน้อย 1 รายการ โดยจะไม่ตรงกับเส้นทางที่ว่างเปล่า ดังนั้น match /cities/{city}/{document=**} จะตรงกับเอกสารในคอลเล็กชันย่อย แต่ไม่ตรงกับเอกสารในคอลเล็กชัน cities ส่วน match /cities/{document=**} จะตรงกับเอกสารทั้งในคอลเล็กชัน cities และคอลเล็กชันย่อย

ไวลด์การ์ดแบบเรียกซ้ำต้องอยู่ท้ายคำสั่งที่ตรงกัน

เวอร์ชัน 2

ในกฎความปลอดภัยเวอร์ชัน 2 ไวลด์การ์ดแบบเรียกซ้ำจะจับคู่รายการเส้นทาง 0 รายการขึ้นไป match/cities/{city}/{document=**} จะจับคู่เอกสารในคอลเล็กชันย่อย ทั้งหมด รวมถึงเอกสารในคอลเล็กชัน cities

คุณต้องเลือกใช้เวอร์ชัน 2 โดยเพิ่ม rules_version = '2'; ที่ด้านบนของ กฎความปลอดภัย

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    // Matches any document in the cities collection as well as any document
    // in a subcollection.
    match /cities/{city}/{document=**} {
      allow read, write: if <condition>;
    }
  }
}

คุณมีไวลด์การ์ดแบบเรียกซ้ำได้มากที่สุด 1 รายการต่อคำสั่งจับคู่ แต่ในเวอร์ชัน 2 คุณวางไวลด์การ์ดนี้ไว้ที่ใดก็ได้ในคำสั่งจับคู่ เช่น

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    // Matches any document in the songs collection group
    match /{path=**}/songs/{song} {
      allow read, write: if <condition>;
    }
  }
}

หากใช้การค้นหากลุ่มคอลเล็กชัน คุณต้องใช้เวอร์ชัน 2 ดูการรักษาความปลอดภัยให้กับการค้นหากลุ่มคอลเล็กชัน

ขีดจำกัดของกฎความปลอดภัย

ขณะทำงานกับกฎความปลอดภัย โปรดทราบขีดจำกัดต่อไปนี้

ขีดจำกัด รายละเอียด
จำนวนการเรียก exists(), get() และ getAfter() สูงสุดต่อคำขอ
  • 10 สำหรับคำขอเอกสารเดียวและคำขอการค้นหา
  • 20 สำหรับการอ่านแบบหลายเอกสาร ธุรกรรม และการเขียนแบบเป็นกลุ่ม ขีดจำกัดก่อนหน้านี้ที่ 10 รายการจะมีผลกับการดำเนินการแต่ละครั้งด้วย

    ตัวอย่างเช่น สมมติว่าคุณสร้างคำขอเขียนแบบกลุ่มที่มี การดำเนินการเขียน 3 รายการ และกฎการรักษาความปลอดภัยใช้การเรียกการเข้าถึงเอกสาร 2 รายการ เพื่อตรวจสอบการเขียนแต่ละรายการ ในกรณีนี้ การเขียนแต่ละครั้งจะใช้การเรียกเข้าถึง 2 ครั้งจาก 10 ครั้ง และคำขอเขียนแบบกลุ่มจะใช้การเรียกเข้าถึง 6 ครั้งจาก 20 ครั้ง

หากเกินขีดจำกัดใดขีดจำกัดหนึ่ง ระบบจะแสดงข้อผิดพลาด "ปฏิเสธสิทธิ์"

ระบบอาจแคชการเรียกใช้การเข้าถึงเอกสารบางรายการ และการเรียกใช้ที่แคชจะไม่นับรวมในโควต้า

ความลึกสูงสุดของคำสั่ง match ที่ซ้อนกัน 10
ความยาวเส้นทางสูงสุดในส่วนเส้นทางที่อนุญาตภายในชุดคำสั่ง match ที่ซ้อนกัน 100
จำนวนตัวแปรการบันทึกเส้นทางสูงสุดที่อนุญาตภายในชุดคำสั่ง match ที่ซ้อนกัน 20
ความลึกสูงสุดของการเรียกใช้ฟังก์ชัน 20
จำนวนอาร์กิวเมนต์ของฟังก์ชันสูงสุด 7
จำนวนการเชื่อมโยงตัวแปร let สูงสุดต่อฟังก์ชัน 10
จำนวนการเรียกฟังก์ชันแบบเรียกซ้ำหรือแบบวนซ้ำสูงสุด 0 &lpar;ไม่อนุญาต&rpar;
จำนวนสูงสุดของนิพจน์ที่ประเมินต่อคำขอ 1,000 ราย
ขนาดสูงสุดของชุดกฎ ชุดกฎต้องมีขนาดไม่เกิน 2 ขีดจำกัดต่อไปนี้
  • จำกัดขนาดของแหล่งที่มาของข้อความชุดกฎที่ 256 KB ซึ่งเผยแพร่จากFirebaseคอนโซลหรือจาก CLI โดยใช้ firebase deploy
  • จำกัดขนาดของชุดกฎที่คอมไพล์แล้วซึ่งเป็นผลลัพธ์ที่ได้เมื่อ Firebase ประมวลผลแหล่งที่มาและทำให้ใช้งานได้ในแบ็กเอนด์ที่ 250 KB

Cloud Storage

โครงสร้างพื้นฐาน

Firebase Security Rules ใน Cloud Firestore และ Cloud Storage ใช้โครงสร้างและไวยากรณ์ต่อไปนี้

service <<name>> {
  // Match the resource path.
  match <<path>> {
    // Allow the request if the following conditions are true.
    allow <<methods>> : if <<condition>>
  }
}

แนวคิดหลักต่อไปนี้เป็นสิ่งสำคัญที่ควรทำความเข้าใจขณะสร้างกฎ

  • คำขอ: เมธอดที่เรียกใช้ในคำสั่ง allow ซึ่งเป็น วิธีการที่คุณอนุญาตให้เรียกใช้ วิธีการมาตรฐาน ได้แก่ get, list, create, update และ delete เมธอดอำนวยความสะดวก read และ write ช่วยให้เข้าถึงการอ่านและการเขียนในเส้นทางฐานข้อมูลหรือที่เก็บข้อมูลที่ระบุได้อย่างกว้างขวาง
  • เส้นทาง: ฐานข้อมูลหรือตำแหน่งที่จัดเก็บซึ่งแสดงเป็นเส้นทาง URI
  • กฎ: คำสั่ง allow ซึ่งมีเงื่อนไขที่อนุญาตคำขอหากประเมินค่าเป็นจริง

เส้นทางที่ตรงกัน

Cloud Storage Security Rules match เส้นทางไฟล์ที่ใช้ในการเข้าถึงไฟล์ใน Cloud Storage กฎสามารถmatchเส้นทางที่แน่นอนหรือเส้นทางที่มีไวลด์การ์ด และ ยังซ้อนกฎได้ด้วย หากไม่มีกฎการจับคู่ที่อนุญาตวิธีการคำขอ หรือ เงื่อนไขประเมินเป็น false ระบบจะปฏิเสธคำขอ

เหมือนกันทุกประการ

// Exact match for "images/profilePhoto.png"
match /images/profilePhoto.png {
  allow write: if <condition>;
}

// Exact match for "images/croppedProfilePhoto.png"
match /images/croppedProfilePhoto.png {
  allow write: if <other_condition>;
}

การจับคู่ที่ซ้อนกัน

// Partial match for files that start with "images"
match /images {
  // Exact match for "images/profilePhoto.png"
  match /profilePhoto.png {
    allow write: if <condition>;
  }

  // Exact match for "images/croppedProfilePhoto.png"
  match /croppedProfilePhoto.png {
    allow write: if <other_condition>;
  }
}

การแข่งขันไวลด์การ์ด

นอกจากนี้ยังใช้กฎเพื่อmatchรูปแบบโดยใช้ไวลด์การ์ดได้ด้วย ไวลด์การ์ดคือตัวแปรที่มีชื่อซึ่งแสดงสตริงเดียว เช่น profilePhoto.png หรือกลุ่มเส้นทางหลายกลุ่ม เช่น images/profilePhoto.png

ระบบจะสร้างไวลด์การ์ดโดยการเพิ่มเครื่องหมายปีกกาคร่อมชื่อไวลด์การ์ด เช่น {string} คุณประกาศไวลด์การ์ดหลายกลุ่มได้โดยเพิ่ม =** ลงใน ชื่อไวลด์การ์ด เช่น {path=**}

// Partial match for files that start with "images"
match /images {
  // Exact match for "images/*"
  // e.g. images/profilePhoto.png is matched
  match /{imageId} {
    // This rule only matches a single path segment (*)
    // imageId is a string that contains the specific segment matched
    allow read: if <condition>;
  }

  // Exact match for "images/**"
  // e.g. images/users/user:12345/profilePhoto.png is matched
  // images/profilePhoto.png is also matched!
  match /{allImages=**} {
    // This rule matches one or more path segments (**)
    // allImages is a path that contains all segments matched
    allow read: if <other_condition>;
  }
}

หากมีหลายกฎที่ตรงกับไฟล์ ผลลัพธ์จะเป็น OR ของผลลัพธ์ของการประเมินกฎทั้งหมด กล่าวคือ หากกฎใดก็ตามที่ไฟล์ตรงกันประเมินเป็น true ผลลัพธ์จะเป็น true

ในกฎ ระบบจะอ่านไฟล์ "images/profilePhoto.png" ได้หากcondition หรือ other_condition ประเมินเป็นจริง ในขณะที่ไฟล์ "images/users/user:12345/profilePhoto.png" จะขึ้นอยู่กับผลลัพธ์ของ other_condition เท่านั้น

คุณอ้างอิงตัวแปรไวลด์การ์ดได้จากภายในmatch provide filename หรือการให้สิทธิ์เส้นทาง

// Another way to restrict the name of a file
match /images/{imageId} {
  allow read: if imageId == "profilePhoto.png";
}

Cloud Storage Security Rules ไม่ได้เรียงซ้อนกัน และระบบจะประเมินกฎก็ต่อเมื่อ เส้นทางคำขอตรงกับเส้นทางที่มีการระบุกฎเท่านั้น

ขอรับการประเมิน

ระบบจะประเมินการอัปโหลด การดาวน์โหลด การเปลี่ยนแปลงข้อมูลเมตา และการลบโดยใช้ request ที่ส่งไปยัง Cloud Storage ตัวแปร request มีเส้นทางที่กำลังดำเนินการคำขอ เวลาที่ได้รับคำขอ และค่า resource ใหม่หากคำขอเป็นการเขียน รวมถึงส่วนหัว HTTP และสถานะการตรวจสอบสิทธิ์ด้วย

ออบเจ็กต์ request ยังมีรหัสที่ไม่ซ้ำของผู้ใช้และ Firebase Authentication เพย์โหลดในออบเจ็กต์ request.auth ซึ่งเราจะ อธิบายเพิ่มเติมในส่วนการตรวจสอบสิทธิ์ ของเอกสาร

ดูรายการพร็อพเพอร์ตี้ทั้งหมดในออบเจ็กต์ request ได้ที่ด้านล่าง

พร็อพเพอร์ตี้ ประเภท คำอธิบาย
auth map<string, string> เมื่อผู้ใช้เข้าสู่ระบบ ระบบจะระบุ uid ซึ่งเป็นรหัสที่ไม่ซ้ำของผู้ใช้ และ token ซึ่งเป็นแผนที่ของอ้างสิทธิ์ JWT Firebase Authentication มิเช่นนั้นจะเป็น null
params map<string, string> แผนที่ที่มีพารามิเตอร์การค้นหาของคำขอ
path เส้นทาง path ที่แสดงเส้นทางที่คำขออยู่ระหว่าง ดำเนินการ
resource map<string, string> ค่าทรัพยากรใหม่ซึ่งจะแสดงในคำขอ write เท่านั้น
time การประทับเวลา การประทับเวลาที่แสดงเวลาเซิร์ฟเวอร์ที่ประเมินคำขอ

การประเมินทรัพยากร

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

Firebase Security Rules สำหรับ Cloud Storage จะให้ข้อมูลเมตาของไฟล์ในออบเจ็กต์ resource ซึ่งมีคู่คีย์/ค่าของข้อมูลเมตาที่แสดงในออบเจ็กต์ Cloud Storage คุณตรวจสอบพร็อพเพอร์ตี้เหล่านี้ได้ในคำขอ read หรือ write เพื่อให้มั่นใจว่าข้อมูลมีความสมบูรณ์

ในwriteคำขอ (เช่น การอัปโหลด การอัปเดตข้อมูลเมตา และการลบ) นอกเหนือจากออบเจ็กต์ resource ซึ่งมีข้อมูลเมตาของไฟล์สำหรับไฟล์ที่อยู่ในเส้นทางคำขอแล้ว คุณยังใช้request.resourceออบเจ็กต์ได้ด้วย ซึ่งมีชุดย่อยของข้อมูลเมตาของไฟล์ที่จะเขียนหากได้รับอนุญาตให้เขียน คุณใช้ค่าทั้ง 2 นี้เพื่อให้มั่นใจในความสมบูรณ์ของข้อมูล หรือบังคับใช้ข้อจํากัดของแอปพลิเคชัน เช่น ประเภทหรือขนาดไฟล์

รายการพร็อพเพอร์ตี้ทั้งหมดในออบเจ็กต์ resource มีดังนี้

พร็อพเพอร์ตี้ ประเภท คำอธิบาย
name สตริง ชื่อเต็มของออบเจ็กต์
bucket สตริง ชื่อของที่เก็บข้อมูลที่ออบเจ็กต์นี้อยู่
generation int Google Cloud Storage ออบเจ็กต์รุ่นของออบเจ็กต์นี้
metageneration int Google Cloud Storage การสร้างข้อมูลเมตาของออบเจ็กต์ของออบเจ็กต์นี้
size int ขนาดของออบเจ็กต์ในหน่วยไบต์
timeCreated การประทับเวลา การประทับเวลาที่แสดงเวลาที่สร้างออบเจ็กต์
updated การประทับเวลา การประทับเวลาที่แสดงเวลาที่อัปเดตออบเจ็กต์ครั้งล่าสุด
md5Hash สตริง แฮช MD5 ของออบเจ็กต์
crc32c สตริง แฮช crc32c ของออบเจ็กต์
etag สตริง แท็ก E ที่เชื่อมโยงกับออบเจ็กต์นี้
contentDisposition สตริง การจัดวางเนื้อหาที่เชื่อมโยงกับออบเจ็กต์นี้
contentEncoding สตริง การเข้ารหัสเนื้อหาที่เชื่อมโยงกับออบเจ็กต์นี้
contentLanguage สตริง ภาษาของเนื้อหาที่เชื่อมโยงกับออบเจ็กต์นี้
contentType สตริง ประเภทเนื้อหาที่เชื่อมโยงกับออบเจ็กต์นี้
metadata map<string, string> คู่คีย์/ค่าของข้อมูลเมตาที่กำหนดเองเพิ่มเติมซึ่งนักพัฒนาแอปเป็นผู้ระบุ

request.resource มีข้อมูลทั้งหมดนี้ ยกเว้น generation, metageneration, etag, timeCreated และ updated

ขีดจำกัดของกฎความปลอดภัย

ขณะทำงานกับกฎความปลอดภัย โปรดทราบขีดจำกัดต่อไปนี้

ขีดจำกัด รายละเอียด
จำนวนการเรียก firestore.exists() และ firestore.get() สูงสุดต่อคำขอ

2 สำหรับคำขอเอกสารเดียวและคำขอการค้นหา

หากเกินขีดจำกัดนี้ ระบบจะแสดงข้อผิดพลาด "ปฏิเสธสิทธิ์"

ระบบอาจแคชการเรียกไปยังเอกสารเดียวกัน และการเรียกที่แคชไว้จะไม่นับรวมในโควต้า

ตัวอย่างแบบเต็ม

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

service firebase.storage {
 match /b/{bucket}/o {
   match /images {
     // Allow write files to the path "images/*", subject to the constraints:
     // 1) File is less than 5MB
     // 2) Content type is an image
     // 3) Uploaded content type matches existing content type
     // 4) Filename (stored in imageId wildcard variable) is less than 32 characters
     match /{imageId} {
       allow read;
       allow write: if request.resource.size < 5 * 1024 * 1024
                    && request.resource.contentType.matches('image/.*')
                    && request.resource.contentType == resource.contentType
                    && imageId.size() < 32
     }
   }
 }
}

Realtime Database

โครงสร้างพื้นฐาน

ใน Realtime Database Firebase Security Rules ประกอบด้วยนิพจน์ที่คล้ายกับ JavaScript ซึ่งอยู่ในเอกสาร JSON

โดยใช้ไวยากรณ์ต่อไปนี้

{
  "rules": {
    "<<path>>": {
    // Allow the request if the condition for each method is true.
      ".read": <<condition>>,
      ".write": <<condition>>,
      ".validate": <<condition>>
    }
  }
}

กฎมีองค์ประกอบพื้นฐาน 3 อย่าง ได้แก่

  • เส้นทาง: ตำแหน่งของฐานข้อมูล ซึ่งจะเหมือนกับโครงสร้าง JSON ของฐานข้อมูล
  • คำขอ: วิธีที่กฎใช้ในการให้สิทธิ์เข้าถึง กฎ read และ write ให้สิทธิ์เข้าถึงแบบอ่านและเขียนในวงกว้าง ขณะที่กฎ validate ทำหน้าที่เป็นการยืนยันรองเพื่อให้สิทธิ์เข้าถึงตามข้อมูลขาเข้าหรือข้อมูลที่มีอยู่
  • เงื่อนไข: เงื่อนไขที่อนุญาตคำขอหากประเมินค่าเป็นจริง

วิธีการใช้กฎกับเส้นทาง

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

โปรดพิจารณากฎต่อไปนี้

{
  "rules": {
     "foo": {
        // allows read to /foo/*
        ".read": "data.child('baz').val() === true",
        "bar": {
          // ignored, since read was allowed already
          ".read": false
        }
     }
  }
}

โครงสร้างความปลอดภัยนี้อนุญาตให้อ่าน /bar/ จากทุกครั้งที่ /foo/ มี baz ย่อยที่มีค่า true กฎ ".read": false ภายใต้ /foo/bar/ จะไม่มีผลในที่นี้ เนื่องจากเส้นทางย่อยไม่สามารถเพิกถอนสิทธิ์เข้าถึงได้

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

อย่างไรก็ตาม .validate กฎจะไม่เรียงซ้อนกัน กฎการตรวจสอบทั้งหมด ต้องเป็นไปตามข้อกำหนดในทุกระดับของลำดับชั้นจึงจะอนุญาตให้เขียนได้

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

{
  "rules": {
    "records": {
      "rec1": {
        ".read": true
      },
      "rec2": {
        ".read": false
      }
    }
  }
}

หากไม่เข้าใจว่ากฎได้รับการประเมินแบบอะตอม คุณอาจคิดว่า การดึงเส้นทาง /records/ จะแสดงผล rec1 แต่ไม่แสดงผล rec2 แต่ผลลัพธ์ที่ได้จริงคือข้อผิดพลาด

JavaScript
var db = firebase.database();
db.ref("records").once("value", function(snap) {
  // success method is not called
}, function(err) {
  // error callback triggered with PERMISSION_DENIED
});
Objective-C
หมายเหตุ: ผลิตภัณฑ์ Firebase นี้ไม่พร้อมใช้งานในเป้าหมาย App Clip
FIRDatabaseReference *ref = [[FIRDatabase database] reference];
[[_ref child:@"records"] observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  // success block is not called
} withCancelBlock:^(NSError * _Nonnull error) {
  // cancel block triggered with PERMISSION_DENIED
}];
Swift
หมายเหตุ: ผลิตภัณฑ์ Firebase นี้ไม่พร้อมใช้งานในเป้าหมาย App Clip
var ref = FIRDatabase.database().reference()
ref.child("records").observeSingleEventOfType(.Value, withBlock: { snapshot in
    // success block is not called
}, withCancelBlock: { error in
    // cancel block triggered with PERMISSION_DENIED
})
Java
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference ref = database.getReference("records");
ref.addListenerForSingleValueEvent(new ValueEventListener() {
  @Override
  public void onDataChange(DataSnapshot snapshot) {
    // success method is not called
  }

  @Override
  public void onCancelled(FirebaseError firebaseError) {
    // error callback triggered with PERMISSION_DENIED
  });
});
REST
curl https://docs-examples.firebaseio.com/rest/records/
# response returns a PERMISSION_DENIED error

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

Attempt to read /records with auth=Success(null)
    /
    /records

No .read rule allowed the operation.
Read was denied.

ระบบปฏิเสธการดำเนินการเนื่องจากไม่มีกฎการอ่านที่อนุญาตให้เข้าถึงเส้นทาง /records/ แต่โปรดทราบว่าระบบไม่เคยประเมินกฎสำหรับ rec1 เนื่องจากไม่ได้อยู่ในเส้นทางที่เราขอ หากต้องการดึงข้อมูล rec1 เราจะต้องเข้าถึงโดยตรง

JavaScript
var db = firebase.database();
db.ref("records/rec1").once("value", function(snap) {
  // SUCCESS!
}, function(err) {
  // error callback is not called
});
Objective-C
หมายเหตุ: ผลิตภัณฑ์ Firebase นี้ไม่พร้อมใช้งานในเป้าหมาย App Clip
FIRDatabaseReference *ref = [[FIRDatabase database] reference];
[[ref child:@"records/rec1"] observeSingleEventOfType:FEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
    // SUCCESS!
}];
Swift
หมายเหตุ: ผลิตภัณฑ์ Firebase นี้ไม่พร้อมใช้งานในเป้าหมาย App Clip
var ref = FIRDatabase.database().reference()
ref.child("records/rec1").observeSingleEventOfType(.Value, withBlock: { snapshot in
    // SUCCESS!
})
Java
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference ref = database.getReference("records/rec1");
ref.addListenerForSingleValueEvent(new ValueEventListener() {
  @Override
  public void onDataChange(DataSnapshot snapshot) {
    // SUCCESS!
  }

  @Override
  public void onCancelled(FirebaseError firebaseError) {
    // error callback is not called
  }
});
REST
curl https://docs-examples.firebaseio.com/rest/records/rec1
# SUCCESS!

ตัวแปรตำแหน่ง

Realtime Database Rules รองรับ$location ตัวแปรเพื่อให้ตรงกับกลุ่มเส้นทาง ใช้คำนำหน้า $ หน้าเส้นทาง ส่วนเพื่อจับคู่กฎกับโหนดลูกใดก็ได้ตามเส้นทาง

  {
    "rules": {
      "rooms": {
        // This rule applies to any child of /rooms/, the key for each room id
        // is stored inside $room_id variable for reference
        "$room_id": {
          "topic": {
            // The room's topic can be changed if the room id has "public" in it
            ".write": "$room_id.contains('public')"
          }
        }
      }
    }
  }

นอกจากนี้ คุณยังใช้ $variable ควบคู่กับชื่อเส้นทางคงที่ได้ด้วย

  {
    "rules": {
      "widget": {
        // a widget can have a title or color attribute
        "title": { ".validate": true },
        "color": { ".validate": true },

        // but no other child paths are allowed
        // in this case, $other means any key excluding "title" and "color"
        "$other": { ".validate": false }
      }
    }
  }