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

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

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

  • ตรวจสอบการตรวจสอบสิทธิ์ผู้ใช้
  • ตรวจสอบข้อมูลขาเข้า

หากต้องการความช่วยเหลือจาก AI ให้คัดลอกพรอมต์ด้านล่างลงในตัวแทนการเขียนโค้ด AI (เช่น Gemini ใน Android Studio, Antigravity, Claude Code, Codex และ Cursor) คุณสามารถปรับแต่งพรอมต์และทำซ้ำกับ Agent ได้ ดูข้อมูลการติดตั้งโดยละเอียดได้ที่ทักษะเอเจนต์ Firebase

Help me use Firebase in my app.
1. Make sure that **Firebase agent skills** are installed and updated. For Claude Code, Codex, or Cursor agents, help me install the Firebase plugin. For other agents, run `npx skills add firebase/agent-skills`. Always try to use **Firebase agent skills** for Firebase-related tasks.
2. Help me write, validate, and deploy Firebase Security Rules to protect my app's Cloud Storage data.

การตรวจสอบสิทธิ์

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

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

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

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

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

  • สาธารณะ: ละเว้น request.auth
  • Authenticated private: check that request.auth is not 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 นอกจากรหัสที่ไม่ซ้ำกันของผู้ใช้และเพย์โหลด 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 object generation ของออบเจ็กต์นี้
metageneration int Google Cloud Storage object 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() ต้องการเส้นทางเอกสารที่ระบุไว้อย่างสมบูรณ์ เมื่อใช้ตัวแปรเพื่อสร้างเส้นทางสำหรับ 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 จะช่วยให้ดูแลรักษาได้ง่ายขึ้นเมื่อกฎมีความซับซ้อนมากขึ้น

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

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

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