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

ใช้เงื่อนไขในกฎความปลอดภัยของ Firebase Cloud Storage

คู่มือนี้สร้างขึ้นจาก การเรียนรู้ไวยากรณ์หลักของคู่มือภาษากฎความปลอดภัยของ Firebase เพื่อแสดงวิธีเพิ่มเงื่อนไขให้กับกฎความปลอดภัย Firebase สำหรับ Cloud Storage

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

  • ตรวจสอบการรับรองความถูกต้องของผู้ใช้
  • ตรวจสอบข้อมูลขาเข้า

การรับรองความถูกต้อง

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

เมื่อผู้ใช้ที่ผ่านการรับรองความถูกต้องดำเนินการร้องขอกับ Cloud Storage ตัวแปร request.auth จะถูกเติมด้วย uid ของผู้ใช้ ( request.auth.uid ) รวมทั้งการอ้างสิทธิ์ของ Firebase Authentication JWT ( request.auth.token )

นอกจากนี้ เมื่อใช้การรับรองความถูกต้องแบบกำหนดเอง การอ้างสิทธิ์เพิ่มเติมจะแสดงในช่อง request.auth.token

เมื่อผู้ใช้ที่ไม่ผ่านการรับรองความถูกต้องทำการร้องขอ ตัวแปร request.auth จะเป็น null

การใช้ข้อมูลนี้ มีวิธีทั่วไปหลายวิธีในการใช้การรับรองความถูกต้องเพื่อรักษาความปลอดภัยไฟล์:

  • สาธารณะ: ละเว้น request.auth
  • รับรองความถูกต้องส่วนตัว: ตรวจสอบว่า request.auth ไม่เป็น null
  • ผู้ใช้ส่วนตัว: ตรวจสอบว่า request.auth.uid เท่ากับพาธ uid
  • จัดกลุ่มส่วนตัว: ตรวจสอบการอ้างสิทธิ์ของโทเค็นที่กำหนดเองเพื่อให้ตรงกับการอ้างสิทธิ์ที่เลือก หรืออ่านข้อมูลเมตาของไฟล์เพื่อดูว่ามีฟิลด์ข้อมูลเมตาอยู่หรือไม่

สาธารณะ

กฎใดๆ ที่ไม่พิจารณาบริบทของ request.auth สามารถถือเป็นกฎ public ได้ เนื่องจากไม่พิจารณาบริบทการรับรองความถูกต้องของผู้ใช้ กฎเหล่านี้มีประโยชน์สำหรับการแสดงข้อมูลสาธารณะ เช่น เนื้อหาของเกม ไฟล์เสียง หรือเนื้อหาคงที่อื่นๆ

// Anyone to read a public image if the file is less than 100kB
// Anyone can upload a public file ending in '.txt'
match /public/{imageId} {
  allow read: if resource.size < 100 * 1024;
  allow write: if imageId.matches(".*\\.txt");
}

ส่วนตัวรับรองความถูกต้อง

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

// Require authentication on all internal image reads
match /internal/{imageId} {
  allow read: if request.auth != null;
}

ผู้ใช้ส่วนตัว

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

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

// Only a user can upload their profile picture, but anyone can view it
match /users/{userId}/profilePicture.png {
  allow read;
  allow write: if request.auth.uid == userId;
}

กลุ่มส่วนตัว

กรณีการใช้งานทั่วไปอีกกรณีหนึ่งคือการอนุญาตสิทธิ์แบบกลุ่มบนวัตถุ เช่น การอนุญาตให้สมาชิกในทีมหลายคนทำงานร่วมกันบนเอกสารที่แชร์ มีหลายวิธีในการทำเช่นนี้:

เมื่อข้อมูลนี้ถูกเก็บไว้ในโทเค็นหรือข้อมูลเมตาของไฟล์ จะสามารถอ้างอิงได้จากภายในกฎ:

// Allow reads if the group ID in your token matches the file metadata's `owner` property
// Allow writes if the group ID is in the user's custom token
match /files/{groupId}/{fileName} {
  allow read: if resource.metadata.owner == request.auth.token.groupId;
  allow write: if request.auth.token.groupId == groupId;
}

ขอการประเมิน

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

วัตถุ 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

เพิ่มประสิทธิภาพด้วย Cloud Firestore

คุณเข้าถึงเอกสารใน Cloud Firestore เพื่อประเมินเกณฑ์การให้สิทธิ์อื่นๆ ได้

เมื่อใช้ฟังก์ชัน firestore.get() และ firestore.exists() กฎความปลอดภัยของคุณสามารถประเมินคำขอที่เข้ามาเทียบกับเอกสารใน Cloud Firestore ฟังก์ชัน firestore.get() และ firestore.exists() ต่างต้องการพาธเอกสารที่ระบุโดยสมบูรณ์ เมื่อใช้ตัวแปรเพื่อสร้างเส้นทางสำหรับ firestore.get() และ firestore.exists() คุณต้องหลีกเลี่ยงตัวแปรอย่างชัดเจนโดยใช้ไวยากรณ์ $(variable)

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

service firebase.storage {
  match /b/{bucket}/o {
    match /users/{club}/files/{fileId} {
      allow read: if club in
        firestore.get(/databases/(default)/documents/users/$(request.auth.id)).memberships
    }
  }
}
ในตัวอย่างถัดไป เฉพาะเพื่อนของผู้ใช้เท่านั้นที่สามารถดูรูปภาพของพวกเขาได้
service firebase.storage {
  match /b/{bucket}/o {
    match /users/{userId}/photos/{fileId} {
      allow read: if
        firestore.exists(/databases/(default)/documents/users/$(userId)/friends/$(request.auth.id))
    }
  }
}

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

คุณสามารถปิดใช้งานคุณลักษณะนี้ได้โดยลบบทบาท IAM ตามที่อธิบายไว้ใน จัดการและปรับใช้กฎความปลอดภัยของ Firebase

ตรวจสอบข้อมูล

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

service firebase.storage {
  match /b/{bucket}/o {
    match /images/{imageId} {
      // Only allow uploads of any image file that's less than 5MB
      allow write: if request.resource.size < 5 * 1024 * 1024
                   && request.resource.contentType.matches('image/.*');
    }
  }
}

ฟังก์ชั่นที่กำหนดเอง

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

  • ฟังก์ชันสามารถมีคำสั่ง return เดียวเท่านั้น ไม่สามารถมีตรรกะเพิ่มเติมใดๆ ตัวอย่างเช่น พวกเขาไม่สามารถดำเนินการวนซ้ำหรือเรียกใช้บริการภายนอกได้
  • ฟังก์ชันสามารถเข้าถึงฟังก์ชันและตัวแปรโดยอัตโนมัติจากขอบเขตที่กำหนดไว้ ตัวอย่างเช่น ฟังก์ชันที่กำหนดภายในขอบเขต service firebase.storage มีสิทธิ์เข้าถึงตัวแปร resource และสำหรับ Cloud Firestore เท่านั้น ฟังก์ชันในตัว เช่น get() และ exists()
  • ฟังก์ชันอาจเรียกใช้ฟังก์ชันอื่นแต่ไม่สามารถเรียกซ้ำได้ ความลึกของ call stack ทั้งหมดจำกัดอยู่ที่ 10
  • ในเวอร์ชัน rules2 ฟังก์ชันสามารถกำหนดตัวแปรโดยใช้คำหลัก let ฟังก์ชันสามารถมีจำนวนการผูกจำนวนเท่าใดก็ได้ แต่ต้องลงท้ายด้วยคำสั่ง return

ฟังก์ชันถูกกำหนดด้วยคีย์เวิร์ดของ function และรับอาร์กิวเมนต์เป็นศูนย์หรือมากกว่านั้น ตัวอย่างเช่น คุณอาจต้องการรวมเงื่อนไขสองประเภทที่ใช้ในตัวอย่างด้านบนเป็นฟังก์ชันเดียว:

service firebase.storage {
  match /b/{bucket}/o {
    // True if the user is signed in or the requested data is 'public'
    function signedInOrPublic() {
      return request.auth.uid != null || resource.data.visibility == 'public';
    }
    match /images/{imageId} {
      allow read, write: if signedInOrPublic();
    }
    match /mp3s/{mp3Ids} {
      allow read: if signedInOrPublic();
    }
  }
}

การใช้ฟังก์ชันในกฎความปลอดภัยของ Firebase ทำให้สามารถบำรุงรักษาได้มากขึ้นตามความซับซ้อนของกฎที่เพิ่มขึ้น

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

หลังจากการอภิปรายเกี่ยวกับเงื่อนไขนี้ คุณมีความเข้าใจกฎที่ซับซ้อนมากขึ้น และพร้อมที่จะ:

เรียนรู้วิธีจัดการกับกรณีการใช้งานหลัก และเรียนรู้เวิร์กโฟลว์สำหรับการพัฒนา ทดสอบ และปรับใช้กฎ: