คู่มือนี้ต่อยอดจากคู่มือเรียนรู้ไวยากรณ์หลักของภาษา Firebase Security Rules เพื่อแสดงวิธีเพิ่มเงื่อนไขลงใน Firebase Security Rules สำหรับ Cloud Storage
องค์ประกอบพื้นฐานหลักของ Cloud Storage Security Rules คือเงื่อนไข เงื่อนไข
คือนิพจน์บูลีนที่กำหนดว่าจะอนุญาตหรือปฏิเสธการดำเนินการหนึ่งๆ
สำหรับกฎพื้นฐาน การใช้ลิเทอรัล true
และ false
เป็นเงื่อนไขจะทำงานได้อย่างสมบูรณ์ แต่Firebase Security RulesสำหรับCloud Storage
ภาษาจะช่วยให้คุณเขียนเงื่อนไขที่ซับซ้อนมากขึ้นได้ ซึ่งจะทำสิ่งต่อไปนี้ได้
- ตรวจสอบการตรวจสอบสิทธิ์ของผู้ใช้
- ตรวจสอบข้อมูลขาเข้า
การตรวจสอบสิทธิ์
Firebase Security Rules สำหรับ 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; }
ผู้ใช้แบบส่วนตัว
Use Case ที่พบบ่อยที่สุดสำหรับ 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; }
กลุ่มส่วนตัว
อีก Use Case ที่พบบ่อยไม่แพ้กันคือการอนุญาตสิทธิ์ของกลุ่มในออบเจ็กต์ เช่น การอนุญาตให้สมาชิกในทีมหลายคนทำงานร่วมกันในเอกสารที่แชร์ คุณทำได้หลายวิธีดังนี้
- สร้าง Firebase Authentication โทเค็นที่กำหนดเอง ซึ่งมีข้อมูลเพิ่มเติมเกี่ยวกับสมาชิกในกลุ่ม (เช่น รหัสกลุ่ม)
- ระบุข้อมูลกลุ่ม (เช่น รหัสกลุ่มหรือรายการ
uid
ที่ได้รับอนุญาต) ในข้อมูลเมตาของไฟล์
เมื่อจัดเก็บข้อมูลนี้ไว้ในโทเค็นหรือข้อมูลเมตาของไฟล์แล้ว คุณจะอ้างอิงข้อมูลนี้ได้ จากภายในกฎ
// 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 นอกเหนือจากรหัสที่ไม่ซ้ำของผู้ใช้และFirebase Authenticationเพย์โหลดในออบเจ็กต์ request.auth
ตามที่อธิบายไว้ข้างต้นแล้ว ตัวแปร request
จะมีเส้นทางไฟล์ที่กำลังดำเนินการคำขอ เวลาที่ได้รับคำขอ และค่า resource
ใหม่ หากคำขอเป็นการเขียน
ออบเจ็กต์ 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 ออบเจ็กต์ metageneration ของออบเจ็กต์นี้ |
size |
int | ขนาดของออบเจ็กต์ในหน่วยไบต์ |
timeCreated |
การประทับเวลา | การประทับเวลาที่แสดงเวลาที่สร้างออบเจ็กต์ |
updated |
การประทับเวลา | การประทับเวลาที่แสดงเวลาที่อัปเดตออบเจ็กต์ครั้งล่าสุด |
md5Hash |
สตริง | แฮช MD5 ของออบเจ็กต์ |
crc32c |
สตริง | แฮช crc32c ของออบเจ็กต์ |
etag |
สตริง | แท็ก E ที่เชื่อมโยงกับออบเจ็กต์นี้ |
contentDisposition |
สตริง | การจัดวางเนื้อหาที่เชื่อมโยงกับออบเจ็กต์นี้ |
contentEncoding |
สตริง | การเข้ารหัสเนื้อหาที่เชื่อมโยงกับออบเจ็กต์นี้ |
contentLanguage |
สตริง | ภาษาของเนื้อหาที่เชื่อมโยงกับออบเจ็กต์นี้ |
contentType |
สตริง | ประเภทเนื้อหาที่เชื่อมโยงกับออบเจ็กต์นี้ |
metadata |
map<string, string> | คู่คีย์/ค่าของข้อมูลเมตาที่กำหนดเองเพิ่มเติมซึ่งนักพัฒนาแอปเป็นผู้ระบุ |
request.resource
มีข้อมูลทั้งหมดนี้ ยกเว้น generation
, metageneration
, etag
, timeCreated
และ updated
ปรับปรุงด้วย Cloud Firestore
คุณเข้าถึงเอกสารใน Cloud Firestore เพื่อประเมินเกณฑ์การให้สิทธิ์อื่นๆ ได้
การใช้ฟังก์ชัน firestore.get()
และ firestore.exists()
ทำให้กฎความปลอดภัยสามารถประเมินคำขอขาเข้ากับเอกสารใน Cloud Firestore ได้
ฟังก์ชัน firestore.get()
และ firestore.exists()
ทั้ง 2 ฟังก์ชันคาดหวังเส้นทางเอกสารที่ระบุอย่างครบถ้วน
เมื่อใช้ตัวแปรเพื่อสร้างเส้นทางสำหรับ
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 Security Rules รายการแรกที่ใช้ฟังก์ชัน Cloud Firestore เหล่านี้แล้ว คุณจะได้รับข้อความแจ้งในคอนโซล Firebase หรือ CLI ของ Firebase เพื่อ เปิดใช้สิทธิ์ในการเชื่อมต่อผลิตภัณฑ์ทั้ง 2 รายการ
คุณปิดใช้ฟีเจอร์นี้ได้โดยนำบทบาท IAM ออกตามที่อธิบายไว้ในจัดการและติดตั้งใช้งานFirebase Security Rules
ตรวจสอบข้อมูล
Firebase Security Rules สำหรับ 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 Security Rulesมีความซับซ้อนมากขึ้น คุณอาจต้องการรวมชุดเงื่อนไข ไว้ในฟังก์ชันที่นำกลับมาใช้ใหม่ได้ในชุดกฎ กฎความปลอดภัย รองรับฟังก์ชันที่กำหนดเอง ไวยากรณ์ของฟังก์ชันที่กำหนดเองจะคล้ายกับ JavaScript แต่Firebase Security Rulesฟังก์ชันจะเขียนในภาษาเฉพาะโดเมน ซึ่งมีข้อจำกัดที่สำคัญบางอย่างดังนี้
- ฟังก์ชันจะมีคำสั่ง
return
ได้เพียงคำสั่งเดียว โดยต้องไม่มี ตรรกะเพิ่มเติม เช่น ไม่สามารถเรียกใช้ลูป หรือเรียกใช้บริการภายนอก - ฟังก์ชันสามารถเข้าถึงฟังก์ชันและตัวแปรจากขอบเขตที่กำหนดไว้ได้โดยอัตโนมัติ
เช่น ฟังก์ชันที่กำหนดภายในขอบเขต
service firebase.storage
จะมีสิทธิ์เข้าถึงตัวแปรresource
และสำหรับ Cloud Firestore เท่านั้น ฟังก์ชันในตัว เช่นget()
และexists()
- ฟังก์ชันอาจเรียกฟังก์ชันอื่นๆ ได้ แต่จะเรียกตัวเองซ้ำไม่ได้ ความลึกของสแต็กการเรียกทั้งหมดถูกจำกัดไว้ที่ 10
- ในเวอร์ชัน
rules2
ฟังก์ชันจะกำหนดตัวแปรได้โดยใช้คีย์เวิร์ดlet
ฟังก์ชันจะมีจำนวนการเชื่อมโยง let เท่าใดก็ได้ แต่ต้องลงท้ายด้วยคำสั่ง return
ฟังก์ชันจะกำหนดด้วยคีย์เวิร์ด function
และรับอาร์กิวเมนต์ 0 รายการขึ้นไป
เช่น คุณอาจต้องการรวมเงื่อนไข 2 ประเภทที่ใช้
ในตัวอย่างข้างต้นเป็นฟังก์ชันเดียว
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 Security Rules จะช่วยให้ดูแลรักษาได้ง่ายขึ้นเมื่อกฎมีความซับซ้อนมากขึ้น
ขั้นตอนถัดไป
หลังจากที่ได้พูดคุยเรื่องเงื่อนไขแล้ว คุณจะมีความเข้าใจเกี่ยวกับกฎที่ซับซ้อนมากขึ้น และพร้อมที่จะทำสิ่งต่อไปนี้
ดูวิธีจัดการกรณีการใช้งานหลักและเวิร์กโฟลว์สำหรับการพัฒนา การทดสอบและการนำกฎไปใช้
- เขียนกฎที่ใช้กับสถานการณ์ทั่วไป
- เสริมความรู้ด้วยการทบทวนสถานการณ์ที่คุณต้องระบุและหลีกเลี่ยงกฎที่ไม่ปลอดภัย
- ทดสอบกฎโดยใช้Cloud Storageโปรแกรมจำลองและคลังทดสอบกฎการรักษาความปลอดภัยเฉพาะ
- ตรวจสอบวิธีการที่ใช้ได้สำหรับการติดตั้งใช้งานRules