Kaynaklar arası ağ istekleri

Normal web sayfaları, uzak sunuculardan veri göndermek ve almak için fetch() veya XMLHttpRequest API'lerini kullanabilir ancak aynı kaynak politikası ile sınırlıdır. İçerik komut dosyaları, içerik komut dosyasının yerleştirildiği web kaynağı adına istekler başlatır. Bu nedenle içerik komut dosyaları da aynı kaynak politikasına tabidir. Uzantı kaynakları çok sınırlı değildir. Bir uzantı hizmet çalışanında veya ön plan sekmesinde çalışan bir komut dosyası, uzantı kaynaktan farklı izinler istediği sürece kaynağının dışındaki uzak sunucularla iletişim kurabilir.

Uzantı kaynağı

Çalışan her uzantı, kendi ayrı güvenlik kaynağında bulunur. Uzatma, ek ayrıcalıklar istemeden yükleme sırasındaki kaynakları almak için fetch()'ü çağırabilir. Örneğin, bir uzantı config_resources/ klasöründe config.json adlı bir JSON yapılandırma dosyası içeriyorsa uzantı, dosyanın içeriğini şu şekilde alabilir:

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

Uzantı, kendisinden başka bir güvenlik kaynağı (ör. https://www.google.com) kullanmaya çalışırsa tarayıcı, uzantı uygun kaynak arası izinler istemediği sürece buna izin vermez.

Kaynaklar arası izinler iste

Bir uzantının kaynağının dışındaki uzak sunuculara erişim isteğinde bulunmak için manifest dosyasının host_permissions bölümüne ana makineler, eşleşme kalıpları veya her ikisi de ekleyin.

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

Kaynaklar arası izin değerleri, aşağıdakiler gibi tam nitelikli ana makine adları olabilir:

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

Ya da aşağıdaki gibi eşleşme kalıpları olabilir:

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

"https://*/" eşleşme kalıbı, erişilebilir tüm alanlara HTTPS erişimine izin verir. Burada eşleşme kalıplarının içerik komut dosyası eşleşme kalıplarına benzer olduğunu ancak ana makineden sonraki tüm yol bilgilerinin yok sayıldığını unutmayın.

Ayrıca, erişimin hem ana makine hem de şema bazında verildiğini unutmayın. Bir uzantı, belirli bir ana makineye veya ana makine grubuna hem güvenli hem de güvenli olmayan HTTP erişimi istiyorsa izinleri ayrı ayrı belirtmelidir:

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

Fetch() ve XMLHttpRequest()

fetch(), özellikle hizmet çalışanları için oluşturuldu ve senkronize işlemlerden uzaklaşan daha geniş bir web trendini takip ediyor. XMLHttpRequest() API, Service Worker dışındaki uzantılarda desteklenir ve çağrılması, uzantı hizmeti çalışanının getirme işleyicisini tetikler. Yeni çalışmada, mümkün olduğunda fetch() adlı iş ortağına öncelik verilmelidir.

Güvenlikle ilgili olarak göz önünde bulundurulması gerekenler

Siteler arası komut dosyası çalıştırma güvenlik açıklarından kaçının

fetch() aracılığıyla alınan kaynakları kullanırken ekran dışı dokümanınızın, yan panelinizin veya pop-up'ınızın siteler arası komut dosyası deneyiminin kurbanı olmamasına dikkat edin. Özellikle innerHTML gibi tehlikeli API'leri kullanmaktan kaçının. Örneğin:

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

Bunun yerine, komut dosyası çalıştırmayan daha güvenli API'leri tercih edin:

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;

İçerik komut dosyasının kaynaklar arası isteklere erişimini sınırlama

Bir içerik komut dosyası adına kaynaktan kaynakya istek gönderirken, içerik komut dosyası kimliğine bürünmeye çalışabilecek kötü amaçlı web sayfalarına karşı dikkatli olun. Özellikle içerik komut dosyalarının isteğe bağlı bir URL istemesine izin vermeyin.

Bir uzantının, içerik komut dosyasının bir öğenin fiyatını bulmasına izin vermek için kaynaktan bağımsız istek gerçekleştirdiği bir örneği ele alalım. Çok güvenli olmayan bir yaklaşım da içerik komut dosyasının arka plan sayfasından getirilecek kaynağı tam olarak belirtmesidir.

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())
);

Yukarıdaki yaklaşımda içerik komut dosyası, uzantının erişebildiği herhangi bir URL'yi getirmesini isteyebilir. Kötü amaçlı bir web sayfası bu tür mesajları taklit edebilir ve uzantıyı kaynak dışı kaynaklara erişim izni vermeye kandırabilir.

Bunun yerine, getirilebilecek kaynakları sınırlayan ileti işleyiciler tasarlayın. Aşağıda, içerik komut dosyası URL'nin tamamını değil, yalnızca itemId değerini sağlar.

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 yerine HTTPS'yi tercih et

Ayrıca, HTTP üzerinden alınan kaynaklara özellikle dikkat edin. Uzantınız saldırgan bir ağda kullanılıyorsa bir ağ saldırganı (diğer adıyla "man-in-the-middle") yanıtı değiştirebilir ve muhtemelen uzantınıza saldırabilir. Bunun yerine, mümkün olduğunda HTTPS'yi tercih edin.

İçerik güvenliği politikasını ayarlama

Manifestinize content_security_policy özelliği ekleyerek uzantınızın varsayılan İçerik Güvenliği Politikası'nı değiştirirseniz bağlanmak istediğiniz tüm ana makinelere izin verilmelidir. Varsayılan politika, ana makinelere olan bağlantıları kısıtlamasa da connect-src veya default-src yönergelerini açıkça eklerken dikkatli olun.