ক্রস-অরিজিন XMLHttpRequest

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

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

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

var xhr = new XMLHttpRequest();
xhr.onreadystatechange = handleStateChange; // Implemented elsewhere.
xhr.open("GET", chrome.extension.getURL('/config_resources/config.json'), true);
xhr.send();

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

ক্রস-অরিজিন অনুমতির জন্য অনুরোধ করা হচ্ছে

ম্যানিফেস্ট ফাইলের পারমিশন বিভাগে হোস্ট অথবা হোস্ট ম্যাচ প্যাটার্ন (বা উভয়ই) যোগ করার মাধ্যমে, এক্সটেনশনটি তার অরিজিনের বাইরের রিমোট সার্ভারগুলিতে অ্যাক্সেসের জন্য অনুরোধ করতে পারে।

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

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

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

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

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

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

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

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

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

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

XMLHttpRequest-এর মাধ্যমে প্রাপ্ত রিসোর্স ব্যবহার করার সময়, আপনার ব্যাকগ্রাউন্ড পেজকে ক্রস-সাইট স্ক্রিপ্টিং-এর শিকার হওয়া থেকে সতর্ক থাকতে হবে। বিশেষত, নীচের মতো বিপজ্জনক API ব্যবহার করা থেকে বিরত থাকুন:

var xhr = new XMLHttpRequest();
xhr.open("GET", "https://api.example.com/data.json", true);
xhr.onreadystatechange = function() {
  if (xhr.readyState == 4) {
    // WARNING! Might be evaluating an evil script!
    var resp = eval("(" + xhr.responseText + ")");
    ...
  }
}
xhr.send();
var xhr = new XMLHttpRequest();
xhr.open("GET", "https://api.example.com/data.json", true);
xhr.onreadystatechange = function() {
  if (xhr.readyState == 4) {
    // WARNING! Might be injecting a malicious script!
    document.getElementById("resp").innerHTML = xhr.responseText;
    ...
  }
}
xhr.send();

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

var xhr = new XMLHttpRequest();
xhr.open("GET", "https://api.example.com/data.json", true);
xhr.onreadystatechange = function() {
  if (xhr.readyState == 4) {
    // JSON.parse does not evaluate the attacker's scripts.
    var resp = JSON.parse(xhr.responseText);
  }
}
xhr.send();
var xhr = new XMLHttpRequest();
xhr.open("GET", "https://api.example.com/data.json", true);
xhr.onreadystatechange = function() {
  if (xhr.readyState == 4) {
    // innerText does not let the attacker inject HTML elements.
    document.getElementById("resp").innerText = xhr.responseText;
  }
}
xhr.send();

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

কোনো কন্টেন্ট স্ক্রিপ্টের পক্ষ থেকে ক্রস-অরিজিন রিকোয়েস্ট করার সময়, এমন ক্ষতিকারক ওয়েব পেজ থেকে সতর্ক থাকুন যেগুলো কন্টেন্ট স্ক্রিপ্টের ছদ্মবেশ ধারণ করার চেষ্টা করতে পারে। বিশেষ করে, কন্টেন্ট স্ক্রিপ্টকে কোনো যথেচ্ছ 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') {
        var 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 ডিরেক্টিভগুলো স্পষ্টভাবে যোগ করার সময় সতর্ক থাকুন।