ক্রস-অরিজিন নেটওয়ার্ক অনুরোধ

সাধারণ ওয়েব পেজগুলো রিমোট সার্ভার থেকে ডেটা পাঠানো ও গ্রহণ করার জন্য fetch() বা XMLHttpRequest API ব্যবহার করতে পারে, কিন্তু সেগুলো ‘সেম অরিজিন পলিসি’ দ্বারা সীমাবদ্ধ। কন্টেন্ট স্ক্রিপ্টগুলো সেই ওয়েব অরিজিনের পক্ষ থেকে রিকোয়েস্ট শুরু করে যেখানে স্ক্রিপ্টটিকে ইনজেক্ট করা হয়েছে এবং তাই কন্টেন্ট স্ক্রিপ্টগুলোও ‘সেম অরিজিন পলিসি’র অধীন। এক্সটেনশন অরিজিনগুলো এতটা সীমাবদ্ধ নয়। একটি এক্সটেনশন সার্ভিস ওয়ার্কার বা ফোরগ্রাউন্ড ট্যাবে চলমান কোনো স্ক্রিপ্ট তার অরিজিনের বাইরের রিমোট সার্ভারের সাথে যোগাযোগ করতে পারে, যতক্ষণ পর্যন্ত এক্সটেনশনটি হোস্ট পারমিশনের জন্য অনুরোধ করে।

এক্সটেনশন উৎস

প্রতিটি চলমান এক্সটেনশন তার নিজস্ব পৃথক নিরাপত্তা অরিজিনের মধ্যে থাকে। অতিরিক্ত কোনো প্রিভিলেজের অনুরোধ না করেই, এক্সটেনশনটি তার ইনস্টলেশনের ভেতরের রিসোর্সগুলো পাওয়ার জন্য fetch() কল করতে পারে। উদাহরণস্বরূপ, যদি কোনো এক্সটেনশনে config_resources/ ফোল্ডারের মধ্যে ` config.json নামের একটি JSON কনফিগারেশন ফাইল থাকে, তবে এক্সটেনশনটি ফাইলটির বিষয়বস্তু এভাবে পুনরুদ্ধার করতে পারে:

const response = await fetch('/config_resources/config.json');
const jsonData = await response.json();

যদি এক্সটেনশনটি তার নিজের সিকিউরিটি অরিজিন ছাড়া অন্য কোনো অরিজিন, যেমন https://www.google.com, থেকে কন্টেন্ট অনুরোধ করার চেষ্টা করে, তবে এক্সটেনশনটির হোস্ট পারমিশন না থাকলে এটিকে একটি ক্রস-অরিজিন অনুরোধ হিসেবে গণ্য করা হবে। কন্টেন্ট স্ক্রিপ্টে ক্রস-অরিজিন অনুরোধগুলোকে সর্বদা এভাবেই গণ্য করা হয়, এমনকি এক্সটেনশনটির হোস্ট পারমিশন থাকলেও।

ক্রস-অরিজিন অনুমতির জন্য অনুরোধ করুন

কোনো এক্সটেনশনের অরিজিনের বাইরের রিমোট সার্ভারগুলিতে অ্যাক্সেসের অনুরোধ করতে, ম্যানিফেস্ট ফাইলের host_permissions বিভাগে hosts, match patterns , অথবা উভয়ই যোগ করুন।

{
  "name": "My extension",
  ...
  "host_permissions": [
    "https://www.google.com/"
  ],
  ...
}

ক্রস-অরিজিন পারমিশন ভ্যালুগুলো সম্পূর্ণ কোয়ালিফাইড হোস্ট নেম হতে পারে, যেমন এইগুলো:

  • "https://www.google.com/"
  • "https://www.gmail.com/"

অথবা এগুলো মিলানোর প্যাটার্নও হতে পারে, যেমন এইগুলো:

  • "https://*.google.com/"
  • "https://*/"

"https://*/" এর একটি ম্যাচ প্যাটার্ন সমস্ত পৌঁছানো যায় এমন ডোমেইনে HTTPS অ্যাক্সেসের অনুমতি দেয়। উল্লেখ্য যে, এখানে ম্যাচ প্যাটার্নগুলো কন্টেন্ট স্ক্রিপ্ট ম্যাচ প্যাটার্নের মতোই, কিন্তু হোস্টের পরে থাকা যেকোনো পাথ তথ্য উপেক্ষা করা হয়।

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

"host_permissions": [
  "http://www.google.com/",
  "https://www.google.com/"
]

Fetch() বনাম XMLHttpRequest()

fetch() বিশেষভাবে সার্ভিস ওয়ার্কারদের জন্য তৈরি করা হয়েছিল এবং এটি সিনক্রোনাস অপারেশন থেকে সরে আসার একটি বৃহত্তর ওয়েব প্রবণতাকে অনুসরণ করে। XMLHttpRequest() API সার্ভিস ওয়ার্কারের বাইরের এক্সটেনশনগুলিতে সমর্থিত, এবং এটিকে কল করলে এক্সটেনশন সার্ভিস ওয়ার্কারের `fetch` হ্যান্ডলারটি ট্রিগার হয়। নতুন কাজে যেখানেই সম্ভব fetch() কে প্রাধান্য দেওয়া উচিত।

নিরাপত্তা সংক্রান্ত বিবেচনা

ক্রস-সাইট স্ক্রিপ্টিং দুর্বলতা এড়িয়ে চলুন

fetch() এর মাধ্যমে প্রাপ্ত রিসোর্স ব্যবহার করার সময়, আপনার অফস্ক্রিন ডকুমেন্ট, সাইড প্যানেল বা পপআপকে ক্রস-সাইট স্ক্রিপ্টিং-এর শিকার হওয়া থেকে সতর্ক থাকতে হবে। বিশেষত, innerHTML এর মতো বিপজ্জনক API ব্যবহার করা থেকে বিরত থাকুন। উদাহরণস্বরূপ:

const response = await fetch("https://api.example.com/data.json");
const jsonData = await response.json();
// WARNING! Might be injecting a malicious script!
document.getElementById("resp").innerHTML = jsonData;
    ...

এর পরিবর্তে, এমন নিরাপদ এপিআই ব্যবহার করুন যা স্ক্রিপ্ট চালায় না:

const response = await fetch("https://api.example.com/data.json");
const jsonData = await response.json();
// JSON.parse does not evaluate the attacker's scripts.
let resp = JSON.parse(jsonData);

const response = await fetch("https://api.example.com/data.json");
const jsonData = response.json();
// textContent does not let the attacker inject HTML elements.
document.getElementById("resp").textContent = jsonData;

ক্রস-অরিজিন অনুরোধের জন্য কন্টেন্ট স্ক্রিপ্ট অ্যাক্সেস সীমিত করুন

কোনো কন্টেন্ট স্ক্রিপ্টের পক্ষ থেকে ক্রস-অরিজিন রিকোয়েস্ট করার সময়, এমন ক্ষতিকারক ওয়েব পেজ থেকে সতর্ক থাকুন যেগুলো কন্টেন্ট স্ক্রিপ্টের ছদ্মবেশ ধারণ করার চেষ্টা করতে পারে। বিশেষ করে, কন্টেন্ট স্ক্রিপ্টকে কোনো যথেচ্ছ URL রিকোয়েস্ট করার অনুমতি দেবেন না।

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

chrome.runtime.onMessage.addListener(
  function(request, sender, sendResponse) {
    if (request.contentScriptQuery == 'fetchUrl') {
      // WARNING: SECURITY PROBLEM - a malicious web page may abuse
      // the message handler to get access to arbitrary cross-origin
      // resources.
      fetch(request.url)
        .then(response => response.text())
        .then(text => sendResponse(text))
        .catch(error => ...)
      return true;  // Will respond asynchronously.
    }
  }
);
chrome.runtime.sendMessage(
  {
    contentScriptQuery: 'fetchUrl',
    url: `https://another-site.com/price-query?itemId=${encodeURIComponent(request.itemId)}`
  },
  response => parsePrice(response.text())
);

উপরোক্ত পদ্ধতিতে, কন্টেন্ট স্ক্রিপ্টটি এক্সটেনশনকে এমন যেকোনো ইউআরএল ফেচ করতে বলতে পারে, যেটিতে এক্সটেনশনটির অ্যাক্সেস আছে। একটি ক্ষতিকারক ওয়েব পেজ এই ধরনের বার্তা জাল করতে এবং এক্সটেনশনকে প্রতারিত করে ক্রস-অরিজিন রিসোর্সে অ্যাক্সেস আদায় করতে সক্ষম হতে পারে।

এর পরিবর্তে, এমন মেসেজ হ্যান্ডলার ডিজাইন করুন যা ফেচ করা যাবে এমন রিসোর্সগুলোকে সীমিত করে। নিচে, কন্টেন্ট স্ক্রিপ্ট দ্বারা শুধুমাত্র itemId প্রদান করা হয়েছে, সম্পূর্ণ URL নয়।

chrome.runtime.onMessage.addListener(
  function(request, sender, sendResponse) {
    if (request.contentScriptQuery == 'queryPrice') {
      const url = `https://another-site.com/price-query?itemId=${encodeURIComponent(request.itemId)}`
      fetch(url)
        .then(response => response.text())
        .then(text => parsePrice(text))
        .then(price => sendResponse(price))
        .catch(error => ...)
      return true;  // Will respond asynchronously.
    }
  }
);
chrome.runtime.sendMessage(
  {contentScriptQuery: 'queryPrice', itemId: 12345},
  price => ...
);

HTTP-এর চেয়ে HTTPS ব্যবহার করা শ্রেয়।

এছাড়াও, HTTP-এর মাধ্যমে প্রাপ্ত রিসোর্স সম্পর্কে বিশেষভাবে সতর্ক থাকুন। যদি আপনার এক্সটেনশনটি কোনো প্রতিকূল নেটওয়ার্কে ব্যবহৃত হয়, তাহলে একজন নেটওয়ার্ক আক্রমণকারী (যাকে 'ম্যান-ইন-দ্য-মিডল' বলা হয়) রেসপন্সটি পরিবর্তন করে আপনার এক্সটেনশনকে আক্রমণ করতে পারে। এর পরিবর্তে, যখনই সম্ভব HTTPS ব্যবহার করুন।

বিষয়বস্তু নিরাপত্তা নীতি সামঞ্জস্য করুন

আপনার ম্যানিফেস্টে ` content_security_policy অ্যাট্রিবিউট যোগ করে যদি আপনি আপনার এক্সটেনশনের ডিফল্ট কন্টেন্ট সিকিউরিটি পলিসি পরিবর্তন করেন, তাহলে আপনাকে নিশ্চিত করতে হবে যে আপনি যে সমস্ত হোস্টের সাথে সংযোগ করতে চান, সেগুলোর অনুমতি আছে। যদিও ডিফল্ট পলিসি হোস্টের সাথে সংযোগ সীমাবদ্ধ করে না, ` connect-src বা default-src ডিরেক্টিভগুলো স্পষ্টভাবে যোগ করার সময় সতর্ক থাকুন।