Realtime Database Security Rules ভাষার মূল সিনট্যাক্স সম্পর্কে জানুন

Firebase রিয়েলটাইম ডেটাবেস নিরাপত্তা নিয়ম আপনাকে আপনার ডেটাবেসে সংরক্ষিত ডেটাতে অ্যাক্সেস নিয়ন্ত্রণ করতে দেয়। ফ্লেক্সিবল রুল সিনট্যাক্স আপনাকে এমন নিয়ম তৈরি করতে দেয় যা আপনার ডেটাবেসে লেখা সমস্ত কিছু থেকে শুরু করে স্বতন্ত্র নোডে অপারেশন পর্যন্ত সবকিছুর সাথে মেলে।

রিয়েল-টাইম ডেটাবেস নিরাপত্তা নিয়ম হল আপনার ডেটাবেসের জন্য ঘোষণামূলক কনফিগারেশন। এর অর্থ হল প্রোডাক্ট লজিক থেকে আলাদাভাবে নিয়মগুলি সংজ্ঞায়িত করা হয়। এর অনেক সুবিধা আছে: ক্লায়েন্টদের নিরাপত্তা এনফোর্স করার দায়িত্ব নিতে হয় না, ত্রুটিপূর্ণ ইমপ্লিমেন্টেশন আপনার ডেটা বিপদে ফেলবে না এবং সম্ভবত সবচেয়ে গুরুত্বপূর্ণ হল, ডেটা সুরক্ষিত রাখার জন্য কোনও মধ্যস্থতাকারী, যেমন সার্ভারের প্রয়োজন নেই।

এই বিষয়ে Realtime Database Security Rules-এর বেসিক সিনট্যাক্স ও স্ট্রাকচার বর্ণনা করা হয়েছে যা সম্পূর্ণ রুলসেট তৈরি করতে ব্যবহার করা হয়।

আপনার নিরাপত্তা সংক্রান্ত নিয়ম সাজানো

Realtime Database-এর নিরাপত্তা সংক্রান্ত নিয়মগুলি জাভাস্ক্রিপ্টের মতো এক্সপ্রেশন দিয়ে তৈরি করা হয় যা JSON ডকুমেন্টে থাকে। আপনার নিয়মের স্ট্রাকচার, ডেটাবেসে স্টোর করা ডেটার স্ট্রাকচার অনুযায়ী হতে হবে।

প্রাথমিক নিয়মগুলি সুরক্ষিত করার জন্য নোডের একটি সেট শনাক্ত করে, অ্যাক্সেস পদ্ধতি (যেমন, রিড, রাইট) এবং শর্তাবলী যার অধীনে অ্যাক্সেস অনুমোদিত বা অস্বীকার করা হয়। নিচের উদাহরণে, আমাদের শর্তাবলী সহজ true এবং false স্টেটমেন্ট হবে, তবে পরবর্তী বিষয়ে আমরা শর্তাবলী প্রকাশ করার আরও ডায়নামিক উপায় কভার করব।

যেমন, আমরা যদি parent_node-এর অধীনে child_node সুরক্ষিত করতে চাই, তাহলে এই সিনট্যাক্স অনুসরণ করতে হবে:

{
  "rules": {
    "parent_node": {
      "child_node": {
        ".read": <condition>,
        ".write": <condition>,
        ".validate": <condition>,
      }
    }
  }
}

এই প্যাটার্ন প্রয়োগ করা যাক। যেমন, ধরা যাক আপনি মেসেজের একটি তালিকা ট্র্যাক করছেন এবং আপনার কাছে এমন ডেটা আছে যা দেখতে এইরকম:

{
  "messages": {
    "message0": {
      "content": "Hello",
      "timestamp": 1405704370369
    },
    "message1": {
      "content": "Goodbye",
      "timestamp": 1405704395231
    },
    ...
  }
}

আপনার নিয়মগুলি একই পদ্ধতিতে সাজানো উচিত। এখানে শুধুমাত্র-পড়ার-জন্য নিরাপত্তা সংক্রান্ত নিয়মের একটি সেট দেওয়া হল যা এই ডেটা স্ট্রাকচারের জন্য উপযুক্ত হতে পারে। এই উদাহরণটি ব্যাখ্যা করে যে আমরা কীভাবে ডেটাবেস নোডগুলি নির্দিষ্ট করি যার উপর নিয়মগুলি প্রযোজ্য এবং সেই নোডগুলিতে নিয়মগুলি মূল্যায়ন করার শর্তগুলি।

{
  "rules": {
    // For requests to access the 'messages' node...
    "messages": {
      // ...and the individual wildcarded 'message' nodes beneath
      // (we'll cover wildcarding variables more a bit later)....
      "$message": {

        // For each message, allow a read operation if <condition>. In this
        // case, we specify our condition as "true", so read access is always granted.
        ".read": "true",

        // For read-only behavior, we specify that for write operations, our
        // condition is false.
        ".write": "false"
      }
    }
  }
}

প্রাথমিক নিয়ম সংক্রান্ত অপারেশন

ডেটার উপর যে ধরনের অপারেশন করা হচ্ছে তার উপর ভিত্তি করে নিরাপত্তা এনফোর্স করার জন্য তিন ধরনের নিয়ম রয়েছে: .write, .read এবং .validate। এখানে তাদের উদ্দেশ্যের একটি সংক্ষিপ্ত বিবরণ দেওয়া হল:

নিয়মের ধরন
.read ব্যবহারকারীকে ডেটা পড়ার অনুমতি দেওয়া হয়েছে কিনা এবং কখন দেওয়া হয়েছে তা বর্ণনা করে।
.write ডেটা লেখার অনুমতি দেওয়া হয়েছে কিনা এবং কখন দেওয়া হয়েছে তা বর্ণনা করে।
.validate সঠিকভাবে ফর্ম্যাট করা ভ্যালু কেমন দেখতে হবে, এতে চাইল্ড অ্যাট্রিবিউট আছে কিনা এবং ডেটার ধরন কী তা নির্ধারণ করে।

ওয়াইল্ডকার্ড ক্যাপচার ভেরিয়েবেল

সব নিয়ম স্টেটমেন্ট নোডকে পয়েন্ট করে। একটি স্টেটমেন্ট নির্দিষ্ট নোডকে নির্দেশ করতে পারে অথবা $ ওয়াইল্ডকার্ড ক্যাপচার ভেরিয়েবল ব্যবহার করে হায়ারার্কির লেভেলে নোডের সেটকে নির্দেশ করতে পারে। পরবর্তী নিয়ম স্টেটমেন্টের মধ্যে ব্যবহারের জন্য নোড কী-এর ভ্যালু স্টোর করতে এই ক্যাপচার ভেরিয়েবল ব্যবহার করুন। এই টেকনিকের সাহায্যে আপনি আরও জটিল Security Rules শর্তাবলী লিখতে পারবেন, এই বিষয়ে আমরা পরবর্তী টপিকে আরও বিস্তারিতভাবে আলোচনা করব।

{
  "rules": {
    "rooms": {
      // this rule applies to any child of /rooms/, the key for each room id
      // is stored inside $room_id variable for reference
      "$room_id": {
        "topic": {
          // the room's topic can be changed if the room id has "public" in it
          ".write": "$room_id.contains('public')"
        }
      }
    }
  }
}

ডায়নামিক $ ভেরিয়েবল কনস্ট্যান্ট পাথ নামের সাথেও ব্যবহার করা যেতে পারে। এই উদাহরণে, আমরা $other ভেরিয়েবল ব্যবহার করে একটি .validate নিয়ম ঘোষণা করছি যা নিশ্চিত করে যে widget-এর title এবং color ছাড়া অন্য কোনও চাইল্ড নেই। এমন কোনও রাইট অপারেশন যা অতিরিক্ত চাইল্ড তৈরি করবে, তা ব্যর্থ হবে।

{
  "rules": {
    "widget": {
      // a widget can have a title or color attribute
      "title": { ".validate": true },
      "color": { ".validate": true },

      // but no other child paths are allowed
      // in this case, $other means any key excluding "title" and "color"
      "$other": { ".validate": false }
    }
  }
}

নিয়ম ক্যাসকেড পড়া ও লেখা

.read এবং .write নিয়ম উপর থেকে নিচে কাজ করে, যেখানে অগভীর নিয়ম গভীর নিয়মকে ওভাররাইড করে। কোনও নিয়ম যদি নির্দিষ্ট কোনও পাথে রিড বা রাইট করার অনুমতি দেয়, তাহলে এটি এর অধীনে থাকা সব চাইল্ড নোডেও অ্যাক্সেস দেয়। নিম্নলিখিত স্ট্রাকচারটি বিবেচনা করুন:

{
  "rules": {
     "foo": {
        // allows read to /foo/*
        ".read": "data.child('baz').val() === true",
        "bar": {
          /* ignored, since read was allowed already */
          ".read": false
        }
     }
  }
}

এই নিরাপত্তা স্ট্রাকচার /bar/-কে যেকোনও সময় থেকে রিড করার অনুমতি দেয় /foo/-এ true ভ্যালু সহ চাইল্ড baz থাকে। /foo/bar/-এর অধীনে ".read": false নিয়মের এখানে কোনও প্রভাব নেই, কারণ চাইল্ড পাথের মাধ্যমে অ্যাক্সেস তুলে নেওয়া যাবে না।

যদিও এটি অবিলম্বে স্বজ্ঞাত বলে মনে নাও হতে পারে, এটি নিয়ম ভাষার একটি শক্তিশালী অংশ এবং ন্যূনতম প্রচেষ্টার সাথে খুব জটিল অ্যাক্সেস বিশেষাধিকার প্রয়োগ করার অনুমতি দেয়। এই গাইডের পরবর্তী অংশে ব্যবহারকারী-ভিত্তিক নিরাপত্তা সম্পর্কে আলোচনা করার সময় এটি ব্যাখ্যা করা হবে।

মনে রাখবেন, .validate নিয়ম ক্যাসকেড করে না। লেখার অনুমতি পেতে হলে হায়ারার্কির সব লেভেলে সব যাচাইকরণ নিয়ম পূরণ করতে হবে।

নিয়ম ফিল্টার নয়

নিয়মগুলি অ্যাটমিক পদ্ধতিতে প্রয়োগ করা হয়। এর অর্থ হল, সেই লোকেশন বা মূল লোকেশনে অ্যাক্সেস দেওয়ার কোনও নিয়ম না থাকলে, রিড বা রাইট অপারেশন অবিলম্বে ব্যর্থ হয়। প্রভাবিত প্রতিটি চাইল্ড পাথ অ্যাক্সেসযোগ্য হলেও, পেরেন্ট লোকেশনে রিড করার প্রসেস সম্পূর্ণভাবে ব্যর্থ হবে। এই স্ট্রাকচারটি বিবেচনা করুন:

{
  "rules": {
    "records": {
      "rec1": {
        ".read": true
      },
      "rec2": {
        ".read": false
      }
    }
  }
}

নিয়মগুলি যে স্বতন্ত্রভাবে মূল্যায়ন করা হয় তা না বুঝলে, মনে হতে পারে যে /records/ পাথ ফেচ করলে rec1 রিটার্ন করবে কিন্তু rec2 নয়। তবে, আসল ফলাফল হল একটি সমস্যা:

জাভাস্ক্রিপ্ট
var db = firebase.database();
db.ref("records").once("value", function(snap) {
  // success method is not called
}, function(err) {
  // error callback triggered with PERMISSION_DENIED
});
Objective-C
মনে রাখবেন: এই Firebase প্রোডাক্ট অ্যাপ ক্লিপ টার্গেটে উপলভ্য নয়।
FIRDatabaseReference *ref = [[FIRDatabase database] reference];
[[_ref child:@"records"] observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
  // success block is not called
} withCancelBlock:^(NSError * _Nonnull error) {
  // cancel block triggered with PERMISSION_DENIED
}];
Swift
মনে রাখবেন: এই Firebase প্রোডাক্ট অ্যাপ ক্লিপ টার্গেটে উপলভ্য নয়।
var ref = FIRDatabase.database().reference()
ref.child("records").observeSingleEventOfType(.Value, withBlock: { snapshot in
    // success block is not called
}, withCancelBlock: { error in
    // cancel block triggered with PERMISSION_DENIED
})
জাভা
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference ref = database.getReference("records");
ref.addListenerForSingleValueEvent(new ValueEventListener() {
  @Override
  public void onDataChange(DataSnapshot snapshot) {
    // success method is not called
  }

  @Override
  public void onCancelled(FirebaseError firebaseError) {
    // error callback triggered with PERMISSION_DENIED
  });
});
REST
curl https://docs-examples.firebaseio.com/rest/records/
# response returns a PERMISSION_DENIED error

যেহেতু /records/-এ রিড অপারেশন অ্যাটমিক এবং এমন কোনও রিড রুল নেই যা /records/-এর অধীনে থাকা সব ডেটায় অ্যাক্সেস দেয়, তাই এটি PERMISSION_DENIED এরর দেখাবে। আমরা যদি আমাদের Firebase কনসোলে নিরাপত্তা সিমুলেটরে এই নিয়মটি মূল্যায়ন করি, তাহলে আমরা দেখতে পাব যে পড়ার অপারেশনটি অস্বীকার করা হয়েছে কারণ কোনও পড়ার নিয়ম /records/ পাথে অ্যাক্সেসের অনুমতি দেয়নি। তবে, মনে রাখবেন যে rec1-এর নিয়ম কখনও মূল্যায়ন করা হয়নি কারণ এটি আমাদের অনুরোধ করা পাথে ছিল না। rec1 ফেচ করতে, আমাদের এটি সরাসরি অ্যাক্সেস করতে হবে:

জাভাস্ক্রিপ্ট
var db = firebase.database();
db.ref("records/rec1").once("value", function(snap) {
  // SUCCESS!
}, function(err) {
  // error callback is not called
});
Objective-C
মনে রাখবেন: এই Firebase প্রোডাক্ট অ্যাপ ক্লিপ টার্গেটে উপলভ্য নয়।
FIRDatabaseReference *ref = [[FIRDatabase database] reference];
[[ref child:@"records/rec1"] observeSingleEventOfType:FEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) {
    // SUCCESS!
}];
Swift
মনে রাখবেন: এই Firebase প্রোডাক্ট অ্যাপ ক্লিপ টার্গেটে উপলভ্য নয়।
var ref = FIRDatabase.database().reference()
ref.child("records/rec1").observeSingleEventOfType(.Value, withBlock: { snapshot in
    // SUCCESS!
})
জাভা
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference ref = database.getReference("records/rec1");
ref.addListenerForSingleValueEvent(new ValueEventListener() {
  @Override
  public void onDataChange(DataSnapshot snapshot) {
    // SUCCESS!
  }

  @Override
  public void onCancelled(FirebaseError firebaseError) {
    // error callback is not called
  }
});
REST
curl https://docs-examples.firebaseio.com/rest/records/rec1
# SUCCESS!

ওভারল্যাপ করা স্টেটমেন্ট

কোনও নোডের ক্ষেত্রে একাধিক নিয়ম প্রযোজ্য হতে পারে। একাধিক নিয়ম এক্সপ্রেশন কোনও নোড শনাক্ত করলে, যেকোনও শর্ত false হলে অ্যাক্সেস মেথড প্রত্যাখ্যান করা হয়:

{
  "rules": {
    "messages": {
      // A rule expression that applies to all nodes in the 'messages' node
      "$message": {
        ".read": "true",
        ".write": "true"
      },
      // A second rule expression applying specifically to the 'message1` node
      "message1": {
        ".read": "false",
        ".write": "false"
      }
    }
  }
}

উপরের উদাহরণে, message1 নোড থেকে ডেটা পড়ার অনুমতি দেওয়া হবে না, কারণ দ্বিতীয় নিয়মটি সবসময় false, যদিও প্রথম নিয়মটি সবসময় true।

পরবর্তী ধাপ

Firebase Realtime Database-এর নিরাপত্তা সংক্রান্ত নিয়ম সম্পর্কে আপনি আরও ভালভাবে বুঝতে পারবেন:

  • Security Rules ল্যাঙ্গুয়েজের পরবর্তী প্রধান কনসেপ্ট, ডায়নামিক শর্তাবলী সম্পর্কে জানুন, যা আপনার Security Rules-কে ব্যবহারকারীর অনুমোদন চেক করতে, বর্তমান ও ইনকামিং ডেটা তুলনা করতে, ইনকামিং ডেটা যাচাই করতে, ক্লায়েন্টের থেকে আসা কোয়েরির স্ট্রাকচার চেক করতে এবং আরও অনেক কিছু করতে সাহায্য করে।

  • নিরাপত্তা সংক্রান্ত সাধারণ ব্যবহারের উদাহরণ এবং Firebase নিরাপত্তা নিয়মের সংজ্ঞা যা সেগুলি সমাধান করে তা পর্যালোচনা করুন।