ধরুন আপনি একটা বাড়ি বানিয়েছেন। বাড়িটা সুন্দর, সব ফার্নিচার গোছানো, সবকিছু ঠিকঠাক। কিন্তু দরজায় কোনো তালা নেই। যে কেউ ঢুকে যেতে পারে, যা খুশি নিয়ে যেতে পারে, এমনকি ঘর ভেঙেও ফেলতে পারে।
Firebase দিয়ে অ্যাপ বানানোও অনেকটা এরকম। Firestore বা Realtime Database হলো আপনার "বাড়ি", আর Security Rules হলো সেই "তালা ও দারোয়ান" যে ঠিক করে দেয় কে ভেতরে ঢুকতে পারবে, কে কী নিতে পারবে, আর কে কিছু বদলাতে পারবে।
সমস্যাটা হয় তখন, যখন নতুন ডেভেলপাররা Firestore বা Realtime Database তৈরি করার পর সেটাকে Test Mode-এই রেখে দেন। Test Mode মানে হলো দরজা পুরোপুরি খোলা—কোনো তালাই নেই। এই অবস্থায় যে কেউ, এমনকি যাদের কোনো Login পর্যন্ত নেই, তারাও আপনার ডাটাবেসের ডেটা পড়তে, পরিবর্তন করতে বা মুছে ফেলতে পারে।
এই সমস্যার সমাধান হিসেবেই Firebase নিয়ে এসেছে Security Rules।
Firebase-এ মূলত দুই ধরনের Database আছে—Firestore এবং Realtime Database (RTDB)। দুটোরই Security Rules লেখার নিয়ম আলাদা, তাই এই পোস্টে দুটোই একসাথে দেখানো হয়েছে।
এই পোস্টে আমরা ধাপে ধাপে জানবো:
- Firebase Security Rules আসলে কী, এবং কেন এটা এত গুরুত্বপূর্ণ
- Firestore Rules লেখার বেসিক গঠন ও ১০টি বাস্তব Example
request.auth,request.resource,resource.data—এই টার্মগুলো আসলে কী বোঝায়- Realtime Database (RTDB) Rules লেখার বেসিক গঠন ও একই ধরনের Example
- Firestore বনাম RTDB Rules-এর মধ্যে মূল পার্থক্য (তুলনা টেবিল)
- একনজরে সবচেয়ে বেশি ব্যবহৃত Condition-গুলোর তালিকা
- প্রোডাকশনে যাওয়ার আগে যে Best Practices মেনে চলা উচিত
Firebase Security Rules আসলে কী?
সহজ ভাষায়, Security Rules হলো একগুচ্ছ নিয়ম যা আপনি Firebase Console-এ লিখে দেন। এই নিয়মগুলো ঠিক করে দেয়:
- কে ডেটা পড়তে পারবে (read)
- কে নতুন ডেটা যোগ করতে পারবে (create)
- কে আগের ডেটা পরিবর্তন করতে পারবে (update)
- কে ডেটা মুছে ফেলতে পারবে (delete)
মনে রাখার সহজ উপায়: আপনার অ্যাপের Frontend কোড (React, JavaScript, ইত্যাদি) যতই সুন্দর হোক না কেন, সেটা আসলে কোনো নিরাপত্তা দেয় না। কারণ যে কেউ চাইলে Browser-এর Developer Console খুলে সরাসরি Firebase-এ Request পাঠাতে পারে, আপনার UI পুরোপুরি বাইপাস করে। তাই আসল নিরাপত্তা তৈরি হয় Server-Side-এ, মানে এই Security Rules-এর মধ্যেই।
অংশ ১: Firestore Security Rules
Firestore Rules-এর বেসিক গঠন (Structure)
প্রতিটি Firestore Rules ফাইল একই কাঠামো দিয়ে শুরু হয়:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if false;
}
}
}
এখানে কয়েকটা জিনিস খেয়াল করুন:
rules_version = '2'— এটা বলে দেয় আপনি Rules-এর নতুন ভার্সন (Version 2) ব্যবহার করছেন।match /{document=**}— এটা মানে "Database-এর যেকোনো Collection-এর যেকোনো Document"। অর্থাৎ এটা একটা Default Rule, যা তখনই কাজ করে যখন নিচে অন্য কোনো নির্দিষ্ট Rule না থাকে।allow read— মানে ডেটা পড়ার (দেখার) অনুমতি।allow write— এটা একসাথে Create, Update এবং Delete—তিনটাকেই বোঝায়।if false— মানে কোনো অবস্থাতেই অনুমতি নেই। এটাই সবচেয়ে নিরাপদ Default অবস্থা।
এখন আমরা ধাপে ধাপে দেখবো কীভাবে এই Default Rule-কে বদলে বাস্তব প্রয়োজন অনুযায়ী কাস্টম Rule বানানো যায়।
Example ১: সবাই পড়তে পারবে, কেউ লিখতে পারবে না
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /posts/{postId} {
allow read: if true;
allow write: if false;
}
}
}
এখানে if true মানে শর্তটা সবসময় সত্যি, তাই সবাই পড়তে পারবে। কিন্তু write এখনও false, তাই কেউ নতুন Post যোগ করতে বা পুরনো Post বদলাতে পারবে না—সেটা শুধু আপনি নিজে Admin Panel বা Backend থেকে করবেন।
এই ধরনের Rule সাধারণত ব্লগ বা নিউজ ওয়েবসাইটে ব্যবহার করা হয়, যেখানে পাঠকরা শুধু পড়বে, কিন্তু কনটেন্ট তৈরি করবে শুধু Admin।
Example ২: শুধু Login করা User লিখতে পারবে
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /posts/{postId} {
allow read: if true;
allow write: if request.auth != null;
}
}
}
এখানে নতুন জিনিসটা হলো request.auth != null। এর মানে হলো—"যদি এই User Login করা থাকে (Firebase Authentication দিয়ে), তাহলেই তাকে লিখতে দাও।"
যদি কেউ Login না করে থাকে, তাহলে Firebase নিজে থেকেই request.auth-কে null (খালি) বানিয়ে দেয়, ফলে Rule সেই Request-কে আটকে দেয়।
Example ৩: প্রত্যেক User শুধু নিজের Profile Edit করতে পারবে
ধরুন আপনার Collection-এর গঠন এরকম:
users
uid123
uid456
এখানে uid123, uid456 হলো প্রতিটা User-এর নিজস্ব Document ID (যেটা সাধারণত তার Firebase Auth UID-এর সাথে মিলিয়ে রাখা হয়)।
match /users/{userId} {
allow read: if true;
allow write: if request.auth.uid == userId;
}
এখানে {userId} হলো একটা Variable, যেটা স্বয়ংক্রিয়ভাবে সেই Document-এর ID ধরে নেয়। তারপর আমরা চেক করছি—Login করা User-এর uid কি এই Document-এর ID-র সাথে মিলছে? মিললে তবেই সে লিখতে পারবে।
সহজ কথায়: আপনি নিজের ঘরে ঢুকতে পারবেন, কিন্তু পাশের ফ্ল্যাটে ঢুকতে পারবেন না—যদিও দুটোই একই বিল্ডিং-এ (একই Collection-এ)।
Example ৪: শুধু Admin ডেটা Delete করতে পারবে
match /posts/{postId} {
allow read: if true;
allow create: if request.auth != null;
allow update: if request.auth != null;
allow delete: if request.auth.token.admin == true;
}
এখানে request.auth.token.admin আসছে Custom Claims থেকে। Custom Claims হলো Firebase Authentication-এর একটা Feature, যেখানে আপনি (Backend থেকে) একটা User-এর Token-এ অতিরিক্ত তথ্য যোগ করে দিতে পারেন—যেমন admin: true।
এভাবে সাধারণ User Post তৈরি বা Update করতে পারলেও, শুধুমাত্র যাদের Token-এ admin: true সেট করা আছে, তারাই Delete করতে পারবে।
Example ৫: শুধু নিজের লেখা Post নিজে Edit করতে পারবে
ধরুন একটা Post Document দেখতে এরকম:
{
"title": "Firebase",
"content": "...",
"authorId": "uid123"
}
Rule:
match /posts/{postId} {
allow read: if true;
allow create:
if request.auth != null;
allow update:
if request.auth.uid == resource.data.authorId;
}
এখানে resource.data.authorId মানে হলো Database-এ আগে থেকেই সেভ থাকা Post-এর authorId ফিল্ড। আমরা সেটাকে Login করা User-এর uid-এর সাথে মিলিয়ে দেখছি—যদি সে-ই আসল লেখক হয়, তবেই Update করতে পারবে।
Example ৬: নতুন Post-এ Title অবশ্যই থাকতে হবে
allow create:
if request.resource.data.title is string
&& request.resource.data.title.size() > 0;
এখানে request.resource.data মানে হলো User এই মুহূর্তে যে নতুন Data পাঠাচ্ছে সেটা (এখনও Database-এ সেভ হয়নি)। আমরা দুটো শর্ত দিচ্ছি:
titleঅবশ্যই একটা Text (string) হতে হবে।- সেই Text-এর দৈর্ঘ্য (
size()) শূন্যের চেয়ে বেশি হতে হবে, মানে খালি রাখা যাবে না।
এইভাবে Rules শুধু "কে করতে পারবে" তাই নয়, বরং "কী ধরনের ডেটা পাঠানো যাবে" সেটাও নিয়ন্ত্রণ করতে পারে। একে বলে Data Validation।
Example ৭: Rating অবশ্যই ১ থেকে ৫-এর মধ্যে হতে হবে
allow create:
if request.resource.data.rating >= 1
&& request.resource.data.rating <= 5;
এভাবে কেউ চাইলেও Rating হিসেবে 10 বা -5-এর মতো ভুল Value পাঠাতে পারবে না। এটা অনেকটা একটা Form-এর Input Validation-এর মতোই, শুধু পার্থক্য হলো এটা Frontend-এ নয়, Server-Side-এ কাজ করে—তাই কেউ চাইলেও ফাঁকি দিতে পারবে না।
Example ৮: শুধুমাত্র Verified Email User Post করতে পারবে
allow create:
if request.auth != null
&& request.auth.token.email_verified == true;
অনেক সময় শুধু Login থাকলেই যথেষ্ট না—আপনি চাইতে পারেন যে User তার Email Verify করেছে কি না সেটাও নিশ্চিত করতে (Spam বা Fake Account ঠেকানোর জন্য)। email_verified হলো Firebase Authentication স্বয়ংক্রিয়ভাবে Token-এ যোগ করে দেওয়া একটা Field।
Example ৯: শুধু Published Post সবাই দেখতে পারবে
allow read:
if resource.data.status == "published";
ধরুন আপনার প্রতিটা Post-এ একটা status Field আছে, যার Value হতে পারে "draft" অথবা "published"। এই Rule দিয়ে আপনি নিশ্চিত করছেন যে সাধারণ Visitor শুধু Published Post-ই দেখতে পাবে, কিন্তু আপনার Draft (অসম্পূর্ণ) লেখাগুলো কারো চোখে পড়বে না।
Example ১০: নিজের Comment নিজেই Delete করতে পারবে
match /comments/{commentId} {
allow delete:
if request.auth.uid == resource.data.userId;
}
এটা Example ৫-এর মতোই লজিক, শুধু এবার Post-এর বদলে Comment-এর জন্য। মানে, একজন User শুধু তার নিজের করা Comment Delete করতে পারবে, অন্য কারো Comment না।
এবার একটু গভীরে যাই: request.auth, request.resource, resource.data কী?
এই তিনটা টার্ম প্রায় সব Rule-এই বারবার আসে, তাই এগুলো ভালোভাবে বুঝে নেওয়া জরুরি।
request.auth — কে Request পাঠাচ্ছে?
- User যদি Login করা থাকে, তাহলে
request.auth-এর ভেতরে তার তথ্য (যেমনuid,token) পাওয়া যায়। - User যদি Login না করা থাকে, তাহলে
request.auth == null।
এটা অনেকটা দারোয়ানের কাছে থাকা ভিজিটর কার্ডের মতো—যার কাছে কার্ড নেই (null), সে ভেতরে ঢুকতে পারবে না যদি Rule সেটা চায়।
request.resource.data — User এখন কী পাঠাচ্ছে?
যখন কেউ নতুন Document তৈরি করে বা পুরনো Document Update করে, তখন সে যে নতুন Data পাঠায়, সেটাই request.resource.data-এর মধ্যে থাকে। যেমন:
request.resource.data.title
এটা এখনো Database-এ সেভ হয়নি—এটা শুধু "আসতে যাচ্ছে" এমন Data।
resource.data — Database-এ আগে থেকে কী আছে?
এটা হলো Document-এ আগে থেকেই সেভ করা Data। যেমন:
resource.data.title
এটা বর্তমান, ইতিমধ্যে Database-এ থাকা Document-এর Title।
সহজ পার্থক্য মনে রাখার উপায়: request.resource.data = "আসছে" (নতুন), resource.data = "আছে" (পুরনো)।
অংশ ২: Realtime Database (RTDB) Security Rules
এতক্ষণ আমরা যা দেখলাম, সবই Firestore-এর জন্য। কিন্তু Firebase-এর পুরনো ও এখনও অনেক প্রজেক্টে ব্যবহৃত হওয়া Database হলো Realtime Database (RTDB)। এর Rules লেখার নিয়ম Firestore থেকে সম্পূর্ণ আলাদা—এখানে JavaScript-এর মতো match ব্লক নেই, বরং পুরো Rule একটা JSON কাঠামোতে লেখা হয়।
RTDB Rules-এর বেসিক গঠন (Structure)
{
"rules": {
".read": false,
".write": false
}
}
এখানে:
.read— কে ডেটা পড়তে পারবে তা ঠিক করে।.write— কে ডেটা লিখতে (Create, Update, Delete—সবকিছু) পারবে তা ঠিক করে।false— Firestore-এর মতোই, এটাই সবচেয়ে নিরাপদ Default অবস্থা, মানে কোনো অনুমতি নেই।
RTDB-তে Data একটা বড় JSON Tree আকারে থাকে, তাই Rules-ও সেই Tree-এর গঠন অনুসরণ করে লেখা হয়—প্রতিটা "Node" বা "Path"-এর জন্য আলাদা করে .read / .write বসানো যায়।
Example ১: সবাই পড়তে পারবে, কেউ লিখতে পারবে না
{
"rules": {
"posts": {
".read": true,
".write": false
}
}
}
এখানে posts Node-এর ভেতরের সব ডেটা যে কেউ পড়তে পারবে, কিন্তু কেউ লিখতে পারবে না।
Example ২: শুধু Login করা User লিখতে পারবে
{
"rules": {
"posts": {
".read": true,
".write": "auth != null"
}
}
}
Firestore-এ যেমন request.auth != null লিখতাম, RTDB-তে শুধু auth != null লিখলেই হয়—এখানে request শব্দটা থাকে না। মনে রাখবেন, RTDB Rules-এর ভেতরে এই Condition-গুলো একটা String আকারে লেখা হয় ("..." এর মধ্যে), কারণ পুরো ফাইলটাই JSON।
Example ৩: প্রত্যেক User শুধু নিজের Profile Edit করতে পারবে
{
"rules": {
"users": {
"$uid": {
".read": true,
".write": "auth != null && auth.uid == $uid"
}
}
}
}
এখানে $uid হলো একটা Wildcard Variable—Firestore-এর {userId}-এর মতোই কাজ করে। এটা স্বয়ংক্রিয়ভাবে সেই মুহূর্তে যে Path অ্যাক্সেস করা হচ্ছে তার নাম ধরে নেয়, এবং সেটাকে Rule-এর মধ্যে ব্যবহার করা যায়।
Example ৪: শুধু Admin ডেটা Delete/লিখতে পারবে
{
"rules": {
"posts": {
".read": true,
".write": "auth != null && auth.token.admin == true"
}
}
}
RTDB-তে Create, Update, Delete—এই তিনটাকে আলাদা করে নিয়ন্ত্রণ করার সুযোগ Firestore-এর মতো সরাসরি নেই। .write একসাথে সবকিছু নিয়ন্ত্রণ করে। তবে চাইলে newData ও data-এর মধ্যে তুলনা করে Create/Update/Delete আলাদা করে সনাক্ত করা যায় (নিচে দেখুন)।
Example ৫: শুধু নিজের লেখা Post নিজে Edit করতে পারবে
{
"rules": {
"posts": {
"$postId": {
".read": true,
".write": "auth != null && (!data.exists() || data.child('authorId').val() == auth.uid)"
}
}
}
}
এখানে দুটো গুরুত্বপূর্ণ Keyword আছে:
data— Firestore-এরresource.data-এর মতো, মানে Database-এ আগে থেকে থাকা ডেটা।newData— Firestore-এরrequest.resource.data-এর মতো, মানে User এখন যে নতুন ডেটা পাঠাচ্ছে।
উপরের Rule-এ !data.exists() চেক করছে এটা নতুন Post কি না (তাহলে যে কেউ Login থাকলেই তৈরি করতে পারবে), আর যদি আগে থেকেই থাকে, তাহলে শুধু আসল Author-ই Update করতে পারবে।
Example ৬: নতুন Post-এ Title অবশ্যই থাকতে হবে
{
"rules": {
"posts": {
"$postId": {
".write": "newData.child('title').isString() && newData.child('title').val().length > 0"
}
}
}
}
এখানে newData.child('title') দিয়ে নতুন পাঠানো Data-এর title Field ধরা হচ্ছে, তারপর সেটা isString() দিয়ে যাচাই করা হচ্ছে এটা Text কি না, এবং .length > 0 দিয়ে খালি নয় কি না।
Example ৭: Rating অবশ্যই ১ থেকে ৫-এর মধ্যে হতে হবে
{
"rules": {
"posts": {
"$postId": {
"rating": {
".validate": "newData.isNumber() && newData.val() >= 1 && newData.val() <= 5"
}
}
}
}
}
এখানে নতুন একটা Keyword দেখা যাচ্ছে—.validate। RTDB-তে .read আর .write দিয়ে বোঝানো হয় "কে করতে পারবে", কিন্তু .validate দিয়ে বোঝানো হয় "ডেটার আকার-আকৃতি কেমন হতে হবে"—অনেকটা Firestore-এর request.resource.data দিয়ে Validation করার মতোই।
Example ৮: শুধু Verified Email User লিখতে পারবে
{
"rules": {
"posts": {
".write": "auth != null && auth.token.email_verified == true"
}
}
}
Firestore-এর মতোই এখানে auth.token.email_verified ব্যবহার করা হচ্ছে, শুধু সামনে request. থাকছে না।
Example ৯: শুধু Published Post সবাই দেখতে পারবে
{
"rules": {
"posts": {
"$postId": {
".read": "data.child('status').val() == 'published'"
}
}
}
}
Example ১০: নিজের Comment নিজেই Delete করতে পারবে
{
"rules": {
"comments": {
"$commentId": {
".write": "auth != null && data.child('userId').val() == auth.uid"
}
}
}
}
RTDB-এ ব্যবহৃত মূল Keyword-গুলো এক নজরে
| Keyword | মানে |
|---|---|
auth |
Login করা User-এর তথ্য (Firestore-এর request.auth) |
data |
Database-এ আগে থেকে থাকা ডেটা (Firestore-এর resource.data) |
newData |
User এখন যে নতুন ডেটা পাঠাচ্ছে (Firestore-এর request.resource.data) |
$variableName |
Path-এর কোনো অংশকে Variable হিসেবে ধরা (Firestore-এর {variableName}) |
.validate |
ডেটার গঠন/মান ঠিক আছে কি না তা যাচাই করা |
Firestore বনাম RTDB: কোনটা কেমন
| বিষয় | Firestore | Realtime Database |
|---|---|---|
| Rule-এর ফরম্যাট | কাস্টম Syntax (match, service) |
সাধারণ JSON |
| Data গঠন | Collection ও Document | একটাই বড় JSON Tree |
| Auth রেফারেন্স | request.auth |
auth |
| পুরনো Data | resource.data |
data |
| নতুন Data | request.resource.data |
newData |
| আলাদা Create/Update/Delete Rule | সরাসরি সম্ভব (allow create, allow update, allow delete) |
সরাসরি সম্ভব না, data/newData তুলনা করে বোঝাতে হয় |
| Data Validation | একই Rule-এর ভেতরে শর্ত হিসেবে | আলাদা .validate Keyword দিয়ে |
সহজ কথায়—নতুন প্রজেক্টের জন্য Google নিজেই Firestore ব্যবহার করার পরামর্শ দেয়, কারণ এটা বেশি Flexible, Query করা সহজ, আর Rules লেখাও তুলনামূলক পরিষ্কার। তবে যদি আপনার প্রজেক্ট আগে থেকেই RTDB-তে বানানো, তাহলে উপরের নিয়মগুলো অনুসরণ করে একইভাবে নিরাপদ করা যায়।
একনজরে সবচেয়ে বেশি ব্যবহৃত Condition-গুলো
| প্রশ্ন | Firestore | RTDB |
|---|---|---|
| User Login আছে? | request.auth != null |
auth != null |
| User Login নেই? | request.auth == null |
auth == null |
| এটা কি এই User-এর নিজের ডেটা? | request.auth.uid == resource.data.userId |
auth.uid == data.child('userId').val() |
| User কি Admin? | request.auth.token.admin == true |
auth.token.admin == true |
| Email কি Verified? | request.auth.token.email_verified == true |
auth.token.email_verified == true |
প্রোডাকশনে যাওয়ার আগে যে Best Practices মেনে চলা উচিত
এই নিয়মগুলো Firestore এবং RTDB—দুটোর জন্যই সমানভাবে প্রযোজ্য:
- কখনোই Production অ্যাপে সব খোলা রেখে দেবেন না—Firestore-এ
allow read, write: if true;অথবা RTDB-তে".read": true, ".write": trueব্যবহার করবেন না। - সবসময় Firebase Authentication-এর সাথে মিলিয়ে Rules লিখুন, শুধু সবসময়-সত্যি শর্ত দিয়ে কাজ চালাবেন না।
- প্রতিটা User যেন শুধুমাত্র তার নিজের ডেটা পরিবর্তন করতে পারে, অন্য কারো নয়।
- গুরুত্বপূর্ণ Collection/Node-গুলোতে (যেমন Post, Comment, Order) অবশ্যই Data Validation যোগ করুন (Firestore-এ শর্ত হিসেবে, RTDB-তে
.validateদিয়ে), যাতে ভুল বা ক্ষতিকর Data ঢুকতে না পারে। - অ্যাপ Live করার আগে Firebase Console-এর Rules Playground দিয়ে বিভিন্ন Scenario টেস্ট করে দেখুন—Rule আসলেই ঠিকঠাক কাজ করছে কি না। Firestore ও RTDB দুটোর জন্যই আলাদা Playground আছে।
- Rules-কে একটা "সেট অ্যান্ড ফরগেট" জিনিস মনে করবেন না—অ্যাপে নতুন Feature বা নতুন Collection/Node যোগ হলে সাথে সাথে সেটার জন্যও Rule লিখুন।
- একই প্রজেক্টে দুটো Database (Firestore + RTDB) ব্যবহার করলে, দুটোর Rules আলাদাভাবে লিখতে ও টেস্ট করতে হবে—একটার Rule অন্যটাকে প্রভাবিত করে না।
শেষ কথা
Firebase Security Rules হলো আপনার Firestore বা Realtime Database-এর প্রথম এবং সবচেয়ে গুরুত্বপূর্ণ প্রতিরক্ষা স্তর। শুধু Authentication যোগ করলেই আপনার অ্যাপ নিরাপদ হয়ে যায় না—Authentication বলে দেয় "কে তুমি", আর Security Rules বলে দেয় "তুমি কী করতে পারবে"। এই দুটো একসাথে কাজ করলেই আসল নিরাপত্তা তৈরি হয়।
আপনি Firestore ব্যবহার করেন বা RTDB, নিয়ম একই থাকে—শুধু Syntax আলাদা। তাই অ্যাপ Live করার আগে প্রতিটা Collection বা Node-এর জন্য আলাদা করে চিন্তা করুন—কে পড়তে পারবে, কে লিখতে পারবে, আর কোন শর্তে পারবে। Authentication ও Validation দুটোই ব্যবহার করুন, আর নিয়মিত Rules Playground দিয়ে টেস্ট করে দেখুন।
এভাবেই আপনার Firebase অ্যাপ হয়ে উঠবে আরও নিরাপদ, নির্ভরযোগ্য এবং সত্যিকার অর্থে প্রোডাকশন-রেডি।