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

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

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 /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 อักขระไวลด์การ์ดแบบย้อนกลับจะจับคู่กับรายการเส้นทางอย่างน้อย 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 โปรดดูการรักษาความปลอดภัยให้กับการค้นหากลุ่มคอลเล็กชัน

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

เอกสารอาจตรงกับ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 or subcollections.
    match /cities/{document=**} {
      allow read, write: if true;
    }
  }
}

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

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

โปรดคำนึงถึงขีดจำกัดต่อไปนี้เมื่อใช้กฎความปลอดภัย

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

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

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

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

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

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การให้สิทธิ์ชื่อไฟล์หรือเส้นทาง ดังนี้

// 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 สตริง ETag ที่เชื่อมโยงกับออบเจ็กต์นี้
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 {
     // 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
     }
   }
 }
}

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