กฎความปลอดภัยทำงานอย่างไร

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

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

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

คลาวด์ไฟร์สโตร์

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

กฎความปลอดภัยของ Firebase ใน 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 /cities/SF หรือใช้ไวด์การ์ดเพื่อชี้ไปยังเอกสารใดๆ ในพาธที่ระบุ เช่นใน match /cities/{city}

ในตัวอย่างข้างต้น คำสั่งการจับคู่ใช้ไวยากรณ์ไวด์การ์ด {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>;
    }
  }
}

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

หากคุณต้องการให้กฎมีผลกับลำดับชั้นเชิงลึกตามอำเภอใจ ให้ใช้ไวยากรณ์ไวด์การ์ดแบบเรียกซ้ำ {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 ไวด์การ์ดแบบเรียกซ้ำจะจับคู่รายการพาธตั้งแต่หนึ่งรายการขึ้นไป ไม่ตรงกับเส้นทางว่าง ดังนั้น match /cities/{city}/{document=**} จะจับคู่เอกสารในคอลเลกชันย่อย แต่ไม่ตรงกับคอลเลกชัน cities ในขณะที่ match /cities/{document=**} ตรงกับทั้งสองเอกสารใน คอลเลกชัน cities และคอลเลกชันย่อย

สัญลักษณ์แทนแบบเรียกซ้ำต้องอยู่ท้ายคำสั่งที่ตรงกัน

เวอร์ชัน 2

ในกฎความปลอดภัยเวอร์ชัน 2 ไวด์การ์ดแบบเรียกซ้ำจะจับคู่รายการพาธเป็นศูนย์หรือมากกว่า 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>;
    }
  }
}

คุณสามารถมีไวด์การ์ดแบบเรียกซ้ำได้มากที่สุดหนึ่งรายการต่อคำสั่งการจับคู่ แต่ในเวอร์ชัน 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 โปรดดู การรักษาความปลอดภัยการสืบค้นกลุ่มคอลเลกชัน

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

เป็นไปได้ที่เอกสารจะตรงกับคำสั่ง match มากกว่าหนึ่งรายการ ในกรณีที่นิพจน์ 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 or subcollections.
    match /cities/{document=**} {
      allow read, write: if true;
    }
  }
}

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

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

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

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

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

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

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

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

การจัดเก็บเมฆ

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

กฎความปลอดภัยของ Firebase ใน 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 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 ชื่อไฟล์หรือการอนุญาตเส้นทาง:

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

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

ขอประเมินผล

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

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

รายการคุณสมบัติทั้งหมดในออบเจ็กต์ request มีอยู่ด้านล่าง:

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

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

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

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

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

รายการคุณสมบัติทั้งหมดในออบเจ็กต์ resource มีอยู่ด้านล่าง:

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

request.resource มีสิ่งเหล่านี้ทั้งหมด ยกเว้น generation , metageneration , etag , timeCreated และ updated

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

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

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

2 สำหรับการร้องขอเอกสารเดี่ยวและการร้องขอแบบสอบถาม

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

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

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

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

service firebase.storage {
 match /b/{bucket}/o {
   match /images {
     // Cascade read to any image type at any path
     match /{allImages=**} {
       allow read;
     }

     // 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) File name (stored in imageId wildcard variable) is less than 32 characters
     match /{imageId} {
       allow write: if request.resource.size < 5 * 1024 * 1024
                    && request.resource.contentType.matches('image/.*')
                    && request.resource.contentType == resource.contentType
                    && imageId.size() < 32
     }
   }
 }
}

ฐานข้อมูลเรียลไทม์

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

ในฐานข้อมูลเรียลไทม์ กฎความปลอดภัยของ Firebase ประกอบด้วยนิพจน์ที่คล้ายกับ JavaScript ที่มีอยู่ในเอกสาร JSON

พวกเขาใช้ไวยากรณ์ต่อไปนี้:

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

มีองค์ประกอบพื้นฐานสามประการในกฎ:

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

กฎมีผลกับเส้นทางอย่างไร

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

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

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

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

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

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

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

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

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

จาวาสคริปต์
var db = firebase.database();
db.ref("records").once("value", function(snap) {
  // success method is not called
}, function(err) {
  // error callback triggered with PERMISSION_DENIED
});
วัตถุประสงค์-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
}];
สวิฟท์
หมายเหตุ: ผลิตภัณฑ์ 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
})
ชวา
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
  });
});
พักผ่อน
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 เราจะต้องเข้าถึงโดยตรง:

จาวาสคริปต์
var db = firebase.database();
db.ref("records/rec1").once("value", function(snap) {
  // SUCCESS!
}, function(err) {
  // error callback is not called
});
วัตถุประสงค์-C
หมายเหตุ: ผลิตภัณฑ์ Firebase นี้ไม่พร้อมใช้งานบนเป้าหมาย App Clip
FIRDatabaseReference *ref = [[FIRDatabase database] reference];
[[ref child:@"records/rec1"] observeSingleEventOfType:FEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
    // SUCCESS!
}];
สวิฟท์
หมายเหตุ: ผลิตภัณฑ์ Firebase นี้ไม่พร้อมใช้งานบนเป้าหมาย App Clip
var ref = FIRDatabase.database().reference()
ref.child("records/rec1").observeSingleEventOfType(.Value, withBlock: { snapshot in
    // SUCCESS!
})
ชวา
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
  }
});
พักผ่อน
curl https://docs-examples.firebaseio.com/rest/records/rec1
# SUCCESS!

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

กฎฐานข้อมูลเรียลไทม์รองรับตัวแปร $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 }
      }
    }
  }