คู่มือนี้ต่อยอดจากคู่มือเรียนรู้ไวยากรณ์หลักของภาษา 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 |
สตริง | Etag ที่เชื่อมโยงกับออบเจ็กต์นี้ |
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)).data.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โปรแกรมจำลองและคลังทดสอบกฎการรักษาความปลอดภัยเฉพาะ
- ตรวจสอบวิธีการที่ใช้ได้สำหรับการติดตั้งใช้งานSecurity Rules