নিরাপদে তথ্য অনুসন্ধান

এই পৃষ্ঠাটি স্ট্রাকচারিং সিকিউরিটি রুলস এবং রাইটিং কন্ডিশনস ফর সিকিউরিটি রুলস-এর ধারণাগুলির উপর ভিত্তি করে তৈরি, যা Cloud Firestore Security Rules কীভাবে কোয়েরির সাথে ইন্টারঅ্যাক্ট করে তা ব্যাখ্যা করে। এটি আপনার লেখা কোয়েরিগুলিকে কীভাবে প্রভাবিত করে সে সম্পর্কে আরও বিস্তারিত আলোচনা করে এবং কীভাবে আপনার কোয়েরিগুলি আপনার সিকিউরিটি রুলসের মতো একই সীমাবদ্ধতা ব্যবহার করে তা নিশ্চিত করে তা বর্ণনা করে। এই পৃষ্ঠাটি limit এবং orderBy মতো কোয়েরি বৈশিষ্ট্যের উপর ভিত্তি করে কোয়েরিগুলিকে অনুমতি বা অস্বীকার করার জন্য সুরক্ষা রুলস কীভাবে লিখতে হয় তাও বর্ণনা করে।

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

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

প্রশ্ন এবং নিরাপত্তা নিয়ম

নিচের উদাহরণগুলি যেমন দেখায়, আপনার নিরাপত্তা নিয়মের সীমাবদ্ধতার সাথে খাপ খাইয়ে আপনার প্রশ্নগুলি লিখতে হবে।

auth.uid উপর ভিত্তি করে নথিগুলি সুরক্ষিত করুন এবং অনুসন্ধান করুন

নিম্নলিখিত উদাহরণটি দেখায় যে কীভাবে একটি নিরাপত্তা নিয়ম দ্বারা সুরক্ষিত নথি পুনরুদ্ধারের জন্য একটি কোয়েরি লিখতে হয়। একটি ডাটাবেস বিবেচনা করুন যেখানে story নথির একটি সংগ্রহ রয়েছে:

/stories/{storyid}

{
  title: "A Great Story",
  content: "Once upon a time...",
  author: "some_auth_id",
  published: false
}

title এবং content ক্ষেত্র ছাড়াও, প্রতিটি নথিতে অ্যাক্সেস নিয়ন্ত্রণের জন্য author এবং published ক্ষেত্রগুলি সংরক্ষণ করা হয়। এই উদাহরণগুলি ধরে নেয় যে অ্যাপটি Firebase প্রমাণীকরণ ব্যবহার করে author ক্ষেত্রটিকে ডকুমেন্ট তৈরিকারী ব্যবহারকারীর UID-তে সেট করে। Firebase প্রমাণীকরণ নিরাপত্তা নিয়মে request.auth ভেরিয়েবলও পূরণ করে।

নিম্নলিখিত নিরাপত্তা নিয়মটি প্রতিটি story লেখকের জন্য পঠন এবং লেখার অ্যাক্সেস সীমাবদ্ধ করার জন্য request.auth এবং resource.data ভেরিয়েবল ব্যবহার করে:

service cloud.firestore {
  match /databases/{database}/documents {
    match /stories/{storyid} {
      // Only the authenticated user who authored the document can read or write
      allow read, write: if request.auth != null && request.auth.uid == resource.data.author;
    }
  }
}

ধরুন আপনার অ্যাপে এমন একটি পৃষ্ঠা রয়েছে যা ব্যবহারকারীকে তাদের লেখা story নথির একটি তালিকা দেখায়। আপনি আশা করতে পারেন যে আপনি এই পৃষ্ঠাটি পূরণ করার জন্য নিম্নলিখিত কোয়েরিটি ব্যবহার করতে পারেন। তবে, এই কোয়েরিটি ব্যর্থ হবে, কারণ এতে আপনার সুরক্ষা নিয়মের মতো একই সীমাবদ্ধতা অন্তর্ভুক্ত নেই:

অবৈধ : কোয়েরি সীমাবদ্ধতাগুলি সুরক্ষা নিয়মের সীমাবদ্ধতার সাথে মেলে না।

// This query will fail
db.collection("stories").get()

বর্তমান ব্যবহারকারী যদি প্রতিটি story ডকুমেন্টের লেখক হন, তবুও কোয়েরিটি ব্যর্থ হয়। এই আচরণের কারণ হল, যখন Cloud Firestore আপনার নিরাপত্তা নিয়ম প্রয়োগ করে, তখন এটি কোয়েরিকে তার সম্ভাব্য ফলাফল সেটের সাথে তুলনা করে মূল্যায়ন করে, আপনার ডাটাবেসের ডকুমেন্টের প্রকৃত বৈশিষ্ট্যের সাথে নয়। যদি কোনও কোয়েরিতে এমন ডকুমেন্ট অন্তর্ভুক্ত থাকে যা আপনার নিরাপত্তা নিয়ম লঙ্ঘন করে, তাহলে কোয়েরিটি ব্যর্থ হবে।

বিপরীতে, নিম্নলিখিত কোয়েরিটি সফল হয়, কারণ এতে author ক্ষেত্রের নিরাপত্তা নিয়মের মতো একই সীমাবদ্ধতা অন্তর্ভুক্ত থাকে:

বৈধ : কোয়েরি সীমাবদ্ধতা নিরাপত্তা নিয়ম সীমাবদ্ধতার সাথে মেলে

var user = firebase.auth().currentUser;

db.collection("stories").where("author", "==", user.uid).get()

একটি ক্ষেত্রের উপর ভিত্তি করে নথি সুরক্ষিত করুন এবং অনুসন্ধান করুন

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

service cloud.firestore {
  match /databases/{database}/documents {
    match /stories/{storyid} {
      // Anyone can read a published story; only story authors can read unpublished stories
      allow read: if resource.data.published == true || (request.auth != null && request.auth.uid == resource.data.author);
      // Only story authors can write
      allow write: if request.auth != null && request.auth.uid == resource.data.author;
    }
  }
}

প্রকাশিত পৃষ্ঠাগুলির কোয়েরিতে নিরাপত্তা নিয়মের মতো একই সীমাবদ্ধতা অন্তর্ভুক্ত থাকতে হবে:

db.collection("stories").where("published", "==", true).get()

কোয়েরি সীমাবদ্ধতা .where("published", "==", true) গ্যারান্টি দেয় যে resource.data.published যেকোনো ফলাফলের জন্য true । অতএব, এই কোয়েরিটি সুরক্ষা নিয়ম পূরণ করে এবং ডেটা পড়ার অনুমতি দেয়।

OR প্রশ্ন

একটি লজিক্যাল OR কোয়েরি ( or , in , অথবা array-contains-any ) একটি নিয়ম সেটের বিপরীতে মূল্যায়ন করার সময়, Cloud Firestore প্রতিটি তুলনামূলক মান আলাদাভাবে মূল্যায়ন করে। প্রতিটি তুলনামূলক মানকে অবশ্যই নিরাপত্তা নিয়মের সীমাবদ্ধতা পূরণ করতে হবে। উদাহরণস্বরূপ, নিম্নলিখিত নিয়মের জন্য:

match /mydocuments/{doc} {
  allow read: if resource.data.x > 5;
}

অবৈধ : কোয়েরি সমস্ত সম্ভাব্য নথির জন্য x > 5 এর গ্যারান্টি দেয় না

// These queries will fail
query(db.collection("mydocuments"),
      or(where("x", "==", 1),
         where("x", "==", 6)
      )
    )

query(db.collection("mydocuments"),
      where("x", "in", [1, 3, 6, 42, 99])
    )

বৈধ : কোয়েরি নিশ্চিত করে যে সমস্ত সম্ভাব্য নথির জন্য x > 5

query(db.collection("mydocuments"),
      or(where("x", "==", 6),
         where("x", "==", 42)
      )
    )

query(db.collection("mydocuments"),
      where("x", "in", [6, 42, 99, 105, 200])
    )

প্রশ্নের সীমাবদ্ধতা মূল্যায়ন করা

আপনার নিরাপত্তা নিয়মগুলি তাদের সীমাবদ্ধতার উপর ভিত্তি করে প্রশ্নগুলি গ্রহণ বা অস্বীকার করতে পারে। request.query ভেরিয়েবলটিতে একটি প্রশ্নের limit , offset এবং orderBy বৈশিষ্ট্য থাকে। উদাহরণস্বরূপ, আপনার নিরাপত্তা নিয়মগুলি এমন যেকোনো প্রশ্নকে অস্বীকার করতে পারে যা একটি নির্দিষ্ট পরিসরে পুনরুদ্ধার করা ডকুমেন্টের সর্বাধিক সংখ্যা সীমাবদ্ধ করে না:

allow list: if request.query.limit <= 10;

নিম্নলিখিত নিয়ম সেটটি দেখায় যে কীভাবে নিরাপত্তা নিয়ম লিখতে হয় যা কোয়েরিতে রাখা সীমাবদ্ধতাগুলি মূল্যায়ন করে। এই উদাহরণটি নিম্নলিখিত পরিবর্তনগুলির সাথে পূর্ববর্তী stories নিয়ম সেটটি প্রসারিত করে:

  • নিয়ম সেটটি পঠনের নিয়মটিকে get এবং list এর নিয়মে বিভক্ত করে।
  • get নিয়মটি একক নথি পুনরুদ্ধারকে পাবলিক নথি বা ব্যবহারকারীর লেখা নথিতে সীমাবদ্ধ করে।
  • list নিয়মটি কোয়েরির ক্ষেত্রে get but-এর মতো একই বিধিনিষেধ প্রযোজ্য। এটি কোয়েরির সীমাও পরীক্ষা করে, তারপর সীমা ছাড়া বা 10-এর বেশি সীমা সহ যেকোনো কোয়েরিকে অস্বীকার করে।
  • কোডের ডুপ্লিকেশন এড়াতে রুলসেটটি একটি authorOrPublished() ফাংশন সংজ্ঞায়িত করে।
service cloud.firestore {

  match /databases/{database}/documents {

    match /stories/{storyid} {

      // Returns `true` if the requested story is 'published'
      // or the user authored the story
      function authorOrPublished() {
        return resource.data.published == true || request.auth.uid == resource.data.author;
      }

      // Deny any query not limited to 10 or fewer documents
      // Anyone can query published stories
      // Authors can query their unpublished stories
      allow list: if request.query.limit <= 10 &&
                     authorOrPublished();

      // Anyone can retrieve a published story
      // Only a story's author can retrieve an unpublished story
      allow get: if authorOrPublished();

      // Only a story's author can write to a story
      allow write: if request.auth.uid == resource.data.author;
    }

  }
}

সংগ্রহ গোষ্ঠীর প্রশ্ন এবং নিরাপত্তা নিয়ম

ডিফল্টরূপে, কোয়েরিগুলি একটি একক সংগ্রহের মধ্যে সীমাবদ্ধ থাকে এবং তারা কেবল সেই সংগ্রহ থেকে ফলাফল পুনরুদ্ধার করে। সংগ্রহ গ্রুপ কোয়েরিগুলির সাহায্যে, আপনি একই আইডি সহ সমস্ত সংগ্রহের সমন্বয়ে গঠিত একটি সংগ্রহ গ্রুপ থেকে ফলাফল পুনরুদ্ধার করতে পারেন। এই বিভাগটি সুরক্ষা নিয়ম ব্যবহার করে আপনার সংগ্রহ গ্রুপ কোয়েরিগুলি কীভাবে সুরক্ষিত করবেন তা বর্ণনা করে।

সংগ্রহ গোষ্ঠীর উপর ভিত্তি করে নথিগুলি সুরক্ষিত এবং অনুসন্ধান করুন

আপনার নিরাপত্তা নিয়মে, আপনাকে অবশ্যই সংগ্রহ গোষ্ঠীর জন্য একটি নিয়ম লিখে সংগ্রহ গোষ্ঠীর প্রশ্নের স্পষ্টভাবে অনুমতি দিতে হবে:

  1. নিশ্চিত করুন যে rules_version = '2'; আপনার রুলসেটের প্রথম লাইন। কালেকশন গ্রুপ কোয়েরির জন্য সিকিউরিটি রুলস ভার্সন ২ এর নতুন রিকার্সিভ ওয়াইল্ডকার্ড {name=**} আচরণ প্রয়োজন।
  2. match /{path=**}/ [COLLECTION_ID] /{doc} ব্যবহার করে আপনার সংগ্রহ গোষ্ঠীর জন্য একটি নিয়ম লিখুন।

উদাহরণস্বরূপ, posts উপ-সংগ্রহ ধারণকারী forum ডকুমেন্টে সংগঠিত একটি ফোরাম বিবেচনা করুন:

/forums/{forumid}/posts/{postid}

{
  author: "some_auth_id",
  authorname: "some_username",
  content: "I just read a great story.",
}

এই অ্যাপ্লিকেশনটিতে, আমরা পোস্টগুলিকে তাদের মালিকদের দ্বারা সম্পাদনাযোগ্য এবং প্রমাণিত ব্যবহারকারীদের দ্বারা পাঠযোগ্য করে তুলি:

service cloud.firestore {
  match /databases/{database}/documents {
    match /forums/{forumid}/posts/{post} {
      // Only authenticated users can read
      allow read: if request.auth != null;
      // Only the post author can write
      allow write: if request.auth != null && request.auth.uid == resource.data.author;
    }
  }
}

যেকোনো অনুমোদিত ব্যবহারকারী যেকোনো একক ফোরামের পোস্ট পুনরুদ্ধার করতে পারবেন:

db.collection("forums/technology/posts").get()

কিন্তু যদি আপনি বর্তমান ব্যবহারকারীকে তাদের পোস্টগুলি সমস্ত ফোরামে দেখাতে চান? আপনি সমস্ত posts সংগ্রহ থেকে ফলাফল পুনরুদ্ধার করতে একটি সংগ্রহ গ্রুপ কোয়েরি ব্যবহার করতে পারেন:

var user = firebase.auth().currentUser;

db.collectionGroup("posts").where("author", "==", user.uid).get()

আপনার নিরাপত্তা নিয়মে, আপনাকে posts সংগ্রহ গোষ্ঠীর জন্য একটি পঠন বা তালিকার নিয়ম লিখে এই প্রশ্নের অনুমতি দিতে হবে:

rules_version = '2';
service cloud.firestore {

  match /databases/{database}/documents {
    // Authenticated users can query the posts collection group
    // Applies to collection queries, collection group queries, and
    // single document retrievals
    match /{path=**}/posts/{post} {
      allow read: if request.auth != null;
    }
    match /forums/{forumid}/posts/{postid} {
      // Only a post's author can write to a post
      allow write: if request.auth != null && request.auth.uid == resource.data.author;

    }
  }
}

তবে মনে রাখবেন, এই নিয়মগুলি ID posts সহ সমস্ত সংগ্রহের ক্ষেত্রে প্রযোজ্য হবে, শ্রেণিবিন্যাস নির্বিশেষে। উদাহরণস্বরূপ, এই নিয়মগুলি নিম্নলিখিত সমস্ত posts সংগ্রহের ক্ষেত্রে প্রযোজ্য:

  • /posts/{postid}
  • /forums/{forumid}/posts/{postid}
  • /forums/{forumid}/subforum/{subforumid}/posts/{postid}

একটি ক্ষেত্রের উপর ভিত্তি করে নিরাপদ সংগ্রহ গ্রুপ প্রশ্ন

একক-সংগ্রহের প্রশ্নের মতো, সংগ্রহের গ্রুপের প্রশ্নেরও আপনার নিরাপত্তা নিয়ম দ্বারা নির্ধারিত সীমাবদ্ধতা পূরণ করতে হবে। উদাহরণস্বরূপ, আমরা প্রতিটি ফোরাম পোস্টে একটি published ক্ষেত্র যোগ করতে পারি যেমনটি আমরা উপরের stories উদাহরণে করেছি:

/forums/{forumid}/posts/{postid}

{
  author: "some_auth_id",
  authorname: "some_username",
  content: "I just read a great story.",
  published: false
}

এরপর আমরা published অবস্থা এবং পোস্ট author উপর ভিত্তি করে posts সংগ্রহ গোষ্ঠীর জন্য নিয়ম লিখতে পারি:

rules_version = '2';
service cloud.firestore {

  match /databases/{database}/documents {

    // Returns `true` if the requested post is 'published'
    // or the user authored the post
    function authorOrPublished() {
      return resource.data.published == true || request.auth.uid == resource.data.author;
    }

    match /{path=**}/posts/{post} {

      // Anyone can query published posts
      // Authors can query their unpublished posts
      allow list: if authorOrPublished();

      // Anyone can retrieve a published post
      // Authors can retrieve an unpublished post
      allow get: if authorOrPublished();
    }

    match /forums/{forumid}/posts/{postid} {
      // Only a post's author can write to a post
      allow write: if request.auth.uid == resource.data.author;
    }
  }
}

এই নিয়মগুলির সাহায্যে, ওয়েব, অ্যাপল এবং অ্যান্ড্রয়েড ক্লায়েন্টরা নিম্নলিখিত প্রশ্নগুলি করতে পারবেন:

  • যে কেউ ফোরামে প্রকাশিত পোস্টগুলি পুনরুদ্ধার করতে পারেন:

    db.collection("forums/technology/posts").where('published', '==', true).get()
    
  • যে কেউ সকল ফোরামে একজন লেখকের প্রকাশিত পোস্ট পুনরুদ্ধার করতে পারেন:

    db.collectionGroup("posts").where("author", "==", "some_auth_id").where('published', '==', true).get()
    
  • লেখকরা সমস্ত ফোরামে তাদের প্রকাশিত এবং অপ্রকাশিত সমস্ত পোস্ট পুনরুদ্ধার করতে পারবেন:

    var user = firebase.auth().currentUser;
    
    db.collectionGroup("posts").where("author", "==", user.uid).get()
    

সংগ্রহ গোষ্ঠী এবং নথির পথের উপর ভিত্তি করে নথিগুলি সুরক্ষিত করুন এবং অনুসন্ধান করুন

কিছু ক্ষেত্রে, আপনি ডকুমেন্ট পাথের উপর ভিত্তি করে সংগ্রহ গ্রুপ কোয়েরি সীমাবদ্ধ করতে চাইতে পারেন। এই সীমাবদ্ধতা তৈরি করতে, আপনি একটি ক্ষেত্রের উপর ভিত্তি করে ডকুমেন্ট সুরক্ষিত এবং কোয়েরি করার জন্য একই কৌশল ব্যবহার করতে পারেন।

এমন একটি অ্যাপ্লিকেশন বিবেচনা করুন যা বিভিন্ন স্টক এবং ক্রিপ্টোকারেন্সি এক্সচেঞ্জের মধ্যে প্রতিটি ব্যবহারকারীর লেনদেনের উপর নজর রাখে:

/ব্যবহারকারী/{ব্যবহারকারী আইডি}/এক্সচেঞ্জ/{এক্সচেঞ্জ আইডি}/লেনদেন/{লেনদেন}

{
  amount: 100,
  exchange: 'some_exchange_name',
  timestamp: April 1, 2019 at 12:00:00 PM UTC-7,
  user: "some_auth_id",
}

user ক্ষেত্রটি লক্ষ্য করুন। যদিও আমরা জানি কোন ব্যবহারকারীর কাছে একটি transaction নথি রয়েছে, ডকুমেন্টের পথ থেকে, আমরা প্রতিটি transaction নথিতে এই তথ্যটি ডুপ্লিকেট করি কারণ এটি আমাদের দুটি জিনিস করতে দেয়:

  • এমন সংগ্রহ গ্রুপ কোয়েরি লিখুন যা কেবলমাত্র সেইসব ডকুমেন্টের মধ্যে সীমাবদ্ধ থাকে যেগুলির ডকুমেন্ট পাথে একটি নির্দিষ্ট /users/{userid} থাকে। উদাহরণস্বরূপ:

    var user = firebase.auth().currentUser;
    // Return current user's last five transactions across all exchanges
    db.collectionGroup("transactions").where("user", "==", user).orderBy('timestamp').limit(5)
    
  • transactions সংগ্রহ গোষ্ঠীর সকল প্রশ্নের জন্য এই বিধিনিষেধ কার্যকর করুন যাতে একজন ব্যবহারকারী অন্য ব্যবহারকারীর transaction নথি পুনরুদ্ধার করতে না পারেন।

আমরা আমাদের নিরাপত্তা নিয়মে এই বিধিনিষেধ প্রয়োগ করি এবং user ক্ষেত্রের জন্য ডেটা যাচাইকরণ অন্তর্ভুক্ত করি:

rules_version = '2';
service cloud.firestore {

  match /databases/{database}/documents {

    match /{path=**}/transactions/{transaction} {
      // Authenticated users can retrieve only their own transactions
      allow read: if resource.data.user == request.auth.uid;
    }

    match /users/{userid}/exchange/{exchangeid}/transactions/{transaction} {
      // Authenticated users can write to their own transactions subcollections
      // Writes must populate the user field with the correct auth id
      allow write: if userid == request.auth.uid && request.data.user == request.auth.uid
    }
  }
}

পরবর্তী পদক্ষেপ