Kaynaklar arası XMLHttpRequest

Normal web sayfaları, uzaktaki veri gönderip almak için XMLHttpRequest nesnesini kullanabilir Bunlar aynı kaynak politikasıyla sınırlandırılmıştır. İçerik komut dosyaları istekleri başlatır içerik komut dosyasının yerleştirildiği web kaynağı ve dolayısıyla içerik komut dosyaları da aynı kaynak politikasına tabidir. (İçerik metinleri CORB'ye tabidir. (Chrome 73'ten ve Chrome 83'ten itibaren CORS'a dahil edilmiştir).) Uzantı kaynakları çok sınırlı değil - komut dosyası bir uzantının arka plan sayfasında veya ön plan sekmesinde yürütmeniz, uzantısı, kaynaklar arası izinler istediği sürece kaynağını kontrol eder.

Uzantı kaynağı

Çalışan her uzantı kendi ayrı güvenlik kaynağı içinde bulunur. Ek istekte bulunmadan ayrıcalıklarından yararlanmasını isterseniz uzantı, kurulumu sırasındaki kaynakları almak için XMLHttpRequest özelliğini kullanabilir. Örneğin, Örneğin, bir uzantı config.json adında bir JSON yapılandırma dosyası içeriyorsa config_resources klasöründe yer alıyorsa uzantı, dosya içeriğini şu şekilde alabilir:

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

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

Kaynaklar arası izinler isteme

manifest dosyasını kaydederseniz uzantı, kaynağının dışındaki uzak sunuculara erişim isteğinde bulunabilir.

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

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

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

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

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

"https://*/" eşleşme kalıbı tüm erişilebilir alanlara HTTPS üzerinden erişim sağlar. Burada, kalıplar, içerik komut dosyası eşleşme kalıplarına benzer ancak yok sayılır.

Ayrıca, erişim izninin hem ana makine hem de şema tarafından verildiğini unutmayın. Bir uzantı hem güvenli hem de güvenli belirli bir ana makineye veya ana makine grubuna güvenli olmayan HTTP erişimi varsa izinleri ayrı ayrı bildirmesi gerekir:

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

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

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

XMLHttpRequest aracılığıyla alınan kaynakları kullanırken arka plan sayfanızın siteler arası komut dosyası çalıştırmanın kurbanı olması. Özellikle, aşağıda bulabilirsiniz:

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

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

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

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

Bir içerik komut dosyası adına kaynaklar arası istekler gerçekleştirirken içerik komut dosyasının kimliğine bürünmeye çalışabilecek kötü amaçlı web sayfaları. Özellikle, izin verilmeyen içerik komut dosyalarını kullanabilirsiniz.

Bir uzantının, içerik komut dosyasına izin vermek için kaynaklar arası istek gerçekleştirdiği bir örneği düşünün bir öğenin fiyatını keşfedebilirsiniz. (Güvenli olmayan) yaklaşımlardan biri, içerik komut dosyasının arka plan sayfasından getirilecek tam kaynağı seçin.

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ıdan, erişimi olan kişilerdir. Kötü amaçlı bir web sayfası, bu tür mesajları taklit edebilir ve uzantıyı merkezler arası kaynaklara erişim izni vererek.

Bunun yerine, getirilebilecek kaynakları sınırlayan ileti işleyiciler tasarlayın. Aşağıda, yalnızca itemId, tam URL tarafından değil, içerik komut dosyası tarafından sağlanır.

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 üzerinden HTTPS'yi tercih etme

Ayrıca, HTTP üzerinden alınan kaynaklara karşı özellikle dikkatli olun. Uzantınız bir ağ saldırganı ("man-in-the-middle" olarak da bilinir) yanıtı değiştirebilir ve muhtemelen uzantınıza saldırabilirsiniz. Bunun yerine, mümkün olduğunda HTTPS'yi tercih edin.

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

Uygulamalar veya uzantılara ilişkin varsayılan İçerik Güvenliği Politikası'nı bir content_security_policy özelliğini kullanıyorsanız, izin verilen tüm ana makinelerin izin veriliyor. Varsayılan politika, ana makinelerle olan bağlantıları kısıtlamasa da connect-src veya default-src yönergelerini açıkça eklerken dikkatli olun.