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

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

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

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

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

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

เมื่อผู้ใช้ที่ได้รับการตรวจสอบสิทธิ์ดำเนินการร้องขอกับ 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 Authentication ในออบเจ็กต์ request.auth ตามที่อธิบายไว้ข้างต้น ตัวแปร request ยังมีพาธของไฟล์ที่คำขอกำลังดำเนินการ เวลาที่ได้รับคำขอ และค่า resource ใหม่หาก คำขอคือการเขียน

ออบเจ็กต์ request ยังประกอบด้วย ID เฉพาะของผู้ใช้และเพย์โหลด Firebase Authentication ในออบเจ็ก request.auth ซึ่งจะอธิบายเพิ่มเติมในส่วน ความปลอดภัยตามผู้ใช้ ของเอกสาร

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

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

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 Storage แรกที่ใช้ฟังก์ชัน 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()
  • ฟังก์ชันอาจเรียกใช้ฟังก์ชันอื่นแต่อาจไม่เรียกซ้ำ ความลึกของสแต็กการโทรทั้งหมดถูกจำกัดไว้ที่ 10
  • ในเวอร์ชัน rules2 ฟังก์ชันสามารถกำหนดตัวแปรโดยใช้คีย์เวิร์ด let ฟังก์ชันสามารถมีจำนวนการเชื่อมโยง 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 ทำให้สามารถบำรุงรักษาได้มากขึ้นเมื่อกฎของคุณมีความซับซ้อนมากขึ้น

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

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

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