क्रॉस-ऑरिजिन नेटवर्क के अनुरोध

आम वेबपेज, रिमोट सर्वर से डेटा भेजने और पाने के लिए, fetch() या XMLHttpRequest एपीआई का इस्तेमाल कर सकते हैं. हालांकि, इन पर सेम ऑरिजिन पॉलिसी लागू होती है. कॉन्टेंट स्क्रिप्ट उस वेब ऑरिजिन की ओर से अनुरोध शुरू करती हैं जिसमें कॉन्टेंट स्क्रिप्ट को जोड़ा गया है. इसलिए, कॉन्टेंट स्क्रिप्ट पर भी सेम ऑरिजिन पॉलिसी लागू होती है. एक्सटेंशन ऑरिजिन पर, सेम ऑरिजिन पॉलिसी लागू नहीं होती. एक्सटेंशन सर्विस वर्कर या फ़ोरग्राउंड टैब में चलने वाली स्क्रिप्ट , अपने ऑरिजिन के बाहर मौजूद रिमोट सर्वर से कम्यूनिकेट कर सकती है . हालांकि, इसके लिए एक्सटेंशन को होस्ट की अनुमतियों का अनुरोध करना होगा.

एक्सटेंशन ऑरिजिन

हर चालू एक्सटेंशन, अपने अलग सुरक्षा ऑरिजिन में मौजूद होता है. अतिरिक्त विशेषाधिकारों का अनुरोध किए बिना, एक्सटेंशन अपने इंस्टॉलेशन में मौजूद रिसॉर्स पाने के लिए, 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 सेक्शन में जोड़ें. यह सेक्शन मेनिफ़ेस्ट फ़ाइल में होता है.

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

क्रॉस-ऑरिजिन अनुमति की वैल्यू, पूरी तरह से क्वालिफ़ाइड होस्टनेम हो सकती हैं. जैसे:

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

या ये मैच पैटर्न हो सकते हैं:

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

"https://*/" का मैच पैटर्न, सभी ऐक्सेस किए जा सकने वाले डोमेन के लिए एचटीटीपीएस ऐक्सेस की अनुमति देता है. ध्यान दें कि यहां मैच पैटर्न, कॉन्टेंट स्क्रिप्ट के मैच पैटर्नकी तरह होते हैं. हालांकि, होस्ट के बाद की पाथ की जानकारी को अनदेखा किया जाता है.

यह भी ध्यान दें कि होस्ट और स्कीम, दोनों के हिसाब से ऐक्सेस दिया जाता है. अगर कोई एक्सटेंशन, किसी दिए गए होस्ट या होस्ट के सेट के लिए, सुरक्षित और असुरक्षित, दोनों तरह के एचटीटीपी ऐक्सेस चाहता है, तो उसे अनुमतियों के बारे में अलग से बताना होगा:

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

`fetch()` बनाम `XMLHttpRequest()`

fetch() को खास तौर पर सर्विस वर्कर के लिए बनाया गया था. यह सिंक्रोनस ऑपरेशन से दूर, वेब के बड़े ट्रेंड को फ़ॉलो करता है. XMLHttpRequest() एपीआई, सर्विस वर्कर के बाहर मौजूद एक्सटेंशन में काम करता है. इसे कॉल करने पर, एक्सटेंशन सर्विस वर्कर का फ़ेच हैंडलर ट्रिगर होता है. नए काम के लिए, जहां भी हो सके fetch() का इस्तेमाल करना चाहिए.

सुरक्षा से जुड़े पहलू

क्रॉस-साइट स्क्रिप्टिंग की कमज़ोरियों से बचें

fetch() के ज़रिए वापस पाए गए रिसॉर्स का इस्तेमाल करते समय, ऑफ़स्क्रीन दस्तावेज़, साइड पैनल या पॉप-अप को क्रॉस-साइट स्क्रिप्टिंग का शिकार होने से बचाना चाहिए. खास तौर पर, innerHTML जैसे खतरनाक एपीआई का इस्तेमाल करने से बचें. उदाहरण के लिए:

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;

क्रॉस-ऑरिजिन अनुरोधों के लिए, कॉन्टेंट स्क्रिप्ट के ऐक्सेस को सीमित करना

कॉन्टेंट स्क्रिप्ट की ओर से क्रॉस-ऑरिजिन अनुरोध करते समय, नुकसान पहुंचाने वाले वेबपेजों से सावधान रहें . ये वेबपेज, कॉन्टेंट स्क्रिप्ट के तौर पर काम करने की कोशिश कर सकते हैं. खास तौर पर, कॉन्टेंट स्क्रिप्ट को किसी भी यूआरएल का अनुरोध करने की अनुमति न दें.

यहां एक उदाहरण दिया गया है, जिसमें कोई एक्सटेंशन, क्रॉस-ऑरिजिन अनुरोध करके, कॉन्टेंट स्क्रिप्ट को किसी आइटम की कीमत का पता लगाने की अनुमति देता है. एक कम सुरक्षित तरीका यह होगा कि कॉन्टेंट स्क्रिप्ट, बैकग्राउंड पेज से फ़ेच किए जाने वाले सटीक रिसॉर्स के बारे में बताए.

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 देती है. पूरा यूआरएल नहीं.

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 => ...
);

एचटीटीपी के बजाय एचटीटीपीएस का इस्तेमाल करना

इसके अलावा, एचटीटीपी के ज़रिए वापस पाए गए रिसॉर्स के बारे में खास तौर पर सावधान रहें. अगर आपके एक्सटेंशन का इस्तेमाल किसी ऐसे नेटवर्क पर किया जाता है जो सुरक्षित नहीं है, तो नेटवर्क पर हमला करने वाला व्यक्ति (जिसे "man-in-the-middle" भी कहा जाता है) जवाब में बदलाव कर सकता है. साथ ही, आपके एक्सटेंशन पर हमला भी कर सकता है. इसके बजाय, जहां भी हो सके एचटीटीपीएस का इस्तेमाल करें.

कॉन्टेंट सुरक्षा नीति में बदलाव करना

अगर आपने अपने मेनिफ़ेस्ट में content_security_policy एट्रिब्यूट जोड़कर, अपने एक्सटेंशन के लिए डिफ़ॉल्ट कॉन्टेंट सुरक्षा नीति में बदलाव किया है, तो आपको यह पक्का करना होगा कि जिन होस्ट से कनेक्ट करना है उन्हें अनुमति मिली हो. डिफ़ॉल्ट नीति, होस्ट से कनेक्शन को सीमित नहीं करती. हालांकि, connect-src या default-src डायरेक्टिव को साफ़ तौर पर जोड़ते समय सावधान रहें.