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

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

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

การประกาศบริการและฐานข้อมูล

Firebase Security Rules for 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 /images/profilePhoto.png

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

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

ในตัวอย่างข้างต้น คำสั่งการทํางานแบบตรงทั้งหมดใช้ไวยากรณ์ไวลด์การ์ด {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:

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

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

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