Catch up on highlights from Firebase at Google I/O 2023. Learn more

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

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

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

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

Cloud Firestore

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

กฎความปลอดภัยของ 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
ขนาดสูงสุดของชุดกฎ ชุดกฎต้องเป็นไปตามขีดจำกัดขนาดสองข้อ:
  • ขีดจำกัด 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 ในออบเจ็ก request.auth ซึ่งจะอธิบายเพิ่มเติมในส่วน การรับรองความถูกต้อง ของเอกสาร

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

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

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/ มี 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 }
      }
    }
  }