เรียนรู้ไวยากรณ์หลักของภาษาของกฎการรักษาความปลอดภัยของ Firebase สำหรับ Cloud Storage

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

คู่มือนี้จะอธิบายไวยากรณ์และโครงสร้างพื้นฐานของ Cloud Storage Security Rules เพื่อสร้างชุดกฎที่สมบูรณ์

การประกาศเกี่ยวกับบริการและฐานข้อมูล

Firebase Security Rules สำหรับ Cloud Storage จะต้องเริ่มต้นด้วยการประกาศต่อไปนี้เสมอ

service firebase.storage {
    // ...
}

การประกาศ service firebase.storage จะกำหนดขอบเขตของกฎไว้ที่ Cloud Storage เพื่อป้องกันไม่ให้เกิดความขัดแย้งระหว่าง Cloud Storage Security Rules กับ กฎสำหรับผลิตภัณฑ์อื่นๆ เช่น Cloud Firestore

กฎการอ่าน/เขียนพื้นฐาน

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

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

service firebase.storage {
  // The {bucket} wildcard indicates we match files in all Cloud Storage buckets
  match /b/{bucket}/o {
    // Match filename
    match /filename {
      allow read: if <condition>;
      allow write: if <condition>;
    }
  }
}

คำสั่ง match ทั้งหมดชี้ไปยังไฟล์ คำสั่ง match สามารถชี้ไปยังไฟล์ที่เฉพาะเจาะจงได้ ดังเช่นใน match /images/profilePhoto.png

จับคู่ไวลด์การ์ด

นอกเหนือจากการชี้ไปยังไฟล์เดียวแล้ว Rules ยังใช้อักขระไวลด์การ์ด เพื่อชี้ไปยังไฟล์ที่มีคำนำหน้าสตริงที่กำหนดในชื่อ รวมถึงเครื่องหมายทับ ได้ด้วย เช่น match /images/{imageId}

ในตัวอย่างข้างต้น คำสั่ง match ใช้ไวยากรณ์ไวลด์การ์ด {imageId} ซึ่งหมายความว่ากฎจะมีผลกับไฟล์ใดก็ตามที่มี /images/ อยู่ที่จุดเริ่มต้นของชื่อ เช่น /images/profilePhoto.png หรือ /images/croppedProfilePhoto.png เมื่อมีการประเมินallowนิพจน์ในคำสั่งที่ตรงกัน ตัวแปร imageId จะเปลี่ยนเป็นชื่อไฟล์รูปภาพ เช่น profilePhoto.png หรือ croppedProfilePhoto.png

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

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

ข้อมูลแบบลำดับชั้น

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

พิจารณาสถานการณ์ของชุดไฟล์ที่มีชื่อขึ้นต้นด้วย /images/ Firebase Security Rules มีผลเฉพาะกับชื่อไฟล์ที่ตรงกัน ดังนั้นการควบคุมการเข้าถึง ที่กำหนดไว้ในก้าน /images/ จะไม่มีผลกับก้าน /mp3s/ แต่ให้เขียนกฎที่ชัดเจนซึ่งตรงกับรูปแบบชื่อไฟล์ต่างๆ แทน

service firebase.storage {
  match /b/{bucket}/o {
    match /images/{imageId} {
      allow read, write: if <condition>;
    }

    // Explicitly define rules for the 'mp3s' pattern
    match /mp3s/{mp3Id} {
      allow read, write: if <condition>;
    }
  }
}

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

service firebase.storage {
  match /b/{bucket}/o {
    match /images {
      // Exact match for "images/profilePhoto.png"
      match /profilePhoto.png {
        allow write: if <condition>;
      }
    }
  }
}
service firebase.storage {
  match /b/{bucket}/o {
    // Exact match for "images/profilePhoto.png"
    match /images/profilePhoto.png {
      allow write: if <condition>;
      }
  }
}

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

นอกเหนือจากไวลด์การ์ดที่ตรงกันและแสดงสตริงที่ส่วนท้ายของชื่อไฟล์แล้ว คุณยังประกาศไวลด์การ์ดหลายส่วนเพื่อการจับคู่ที่ซับซ้อนยิ่งขึ้นได้โดย การเพิ่ม =** ลงในชื่อไวลด์การ์ด เช่น {path=**}

// Partial match for files that start with "images"
match /images {

  // 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 เท่านั้น

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

เวอร์ชัน 1

Firebase Security Rules ใช้เวอร์ชัน 1 โดยค่าเริ่มต้น ในเวอร์ชัน 1 ไวลด์การ์ดแบบเรียกซ้ำ จะตรงกับองค์ประกอบชื่อไฟล์อย่างน้อย 1 รายการ ไม่ใช่ 0 รายการขึ้นไป ดังนั้น match /images/{filenamePrefixWildcard}/{imageFilename=**} จะตรงกับชื่อไฟล์ เช่น /images/profilePics/profile.png แต่ไม่ตรงกับ /images/badge.png โปรดใช้ /images/{imagePrefixorFilename=**} แทน

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

เราขอแนะนำให้ใช้เวอร์ชัน 2 เนื่องจากมีฟีเจอร์ที่ทรงพลังกว่า

เวอร์ชัน 2

ในเวอร์ชัน 2 ของ Firebase Security Rules ไวลด์การ์ดแบบเรียกซ้ำจะจับคู่รายการเส้นทาง 0 รายการขึ้นไป ดังนั้น /images/{filenamePrefixWildcard}/{imageFilename=**} จะตรงกับ ชื่อไฟล์ /images/profilePics/profile.png และ /images/badge.png

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

rules_version = '2';
service cloud.storage {
  match /b/{bucket}/o {
   ...
 }
}

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

rules_version = '2';
service firebase.storage {
 match /b/{bucket}/o {
   // Matches any file in a songs "subdirectory" under the
   // top level of your Cloud Storage bucket.
   match /{prefixSegment=**}/songs/{mp3filenames} {
     allow read, write: if <condition>;
   }
  }
}

การดำเนินการแบบละเอียด

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

read สามารถแบ่งออกเป็นgetและlist

write สามารถแบ่งออกเป็น create, update และ delete ได้ดังนี้

service firebase.storage {
  match /b/{bucket}/o {
    // A read rule can be divided into read and list rules
    match /images/{imageId} {
      // Applies to single file read requests
      allow get: if <condition>;
      // Applies to list and listAll requests (Rules Version 2)
      allow list: if <condition>;

    // A write rule can be divided into create, update, and delete rules
    match /images/{imageId} {
      // Applies to writes to file contents
      allow create: if <condition>;

      // Applies to updates to (pre-existing) file metadata
      allow update: if <condition>;

      // Applies to delete operations
      allow delete: if <condition>;
    }
  }
 }
}

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

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

service firebase.storage {
  match b/{bucket}/o {
    // Matches file names directly inside of '/images/'.
    match /images/{imageId} {
      allow read, write: if false;
    }

    // Matches file names anywhere under `/images/`
    match /images/{imageId=**} {
      allow read, write: if true;
    }
  }
}

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

กฎไม่ใช่ตัวกรอง

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

ตัวอย่างเช่น ลองดูที่กฎความปลอดภัยต่อไปนี้

service firebase.storage {
  match /b/{bucket}/o {
    // Allow the client to read files with contentType 'image/png'
    match /aFileNamePrefix/{aFileName} {
      allow read: if resource.contentType == 'image/png';
    }
  }
}

ถูกปฏิเสธ: กฎนี้ปฏิเสธคำขอต่อไปนี้ เนื่องจากชุดผลลัพธ์อาจมีไฟล์ที่ contentType ไม่ได้image/png

เว็บ
filesRef = storage.ref().child("aFilenamePrefix");

filesRef.listAll()
    .then(function(result) {
      console.log("Success: ", result.items);
    })
});

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

ขั้นตอนถัดไป

คุณสามารถทำความเข้าใจเกี่ยวกับ Firebase Security Rules สำหรับ Cloud Storage ได้ลึกซึ้งยิ่งขึ้นโดยทำดังนี้

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

  • ดูกรณีการใช้งานด้านความปลอดภัยทั่วไปและFirebase Security Rulesคำจำกัดความที่เกี่ยวข้อง

คุณสามารถดูFirebase Security Rulesกรณีการใช้งานที่เฉพาะเจาะจงสำหรับ Cloud Storage ได้