跨源 XMLHttpRequest

常规网页可以使用 XMLHttpRequest 对象从远程访问 但又受到同源政策的限制。内容脚本发起请求 代表已注入内容脚本的网络来源,从而 脚本还要遵守同源政策。(内容脚本受 CORB 的约束 从 Chrome 73 开始,从 Chrome 83 开始提供 CORS。)扩展程序的来源并不受限 - 脚本 在扩展程序的后台页面或前台标签页中执行操作时,可以与 前提是该扩展程序请求跨源权限。

扩展程序来源

每个正在运行的扩展程序都存在于各自的安全源中。无需额外请求 特权,该扩展程序可以在其安装中使用 XMLHttpRequest 获取资源。对于 例如,如果扩展程序包含名为 config.json 的 JSON 配置文件,则位于 config_resources 文件夹中,该扩展程序可以检索文件的内容,如下所示:

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, 除非该扩展程序已请求适当的跨源 权限。

请求跨源权限

通过将主机和/或主机匹配模式(或两者)添加到 manifest 文件,该扩展程序可以请求访问其源之外的远程服务器。

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

相反,建议使用不运行脚本且更安全的 API:

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

限制对跨源请求的内容脚本访问

代表内容脚本执行跨源请求时,请注意 的恶意网页。具体来说,不允许 内容脚本来请求任意网址。

假设某个扩展程序会执行跨源请求以允许内容脚本访问 了解商品的价格。一种(不安全)方法是让内容脚本指定 后台网页要提取的确切资源。

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

首选 HTTPS 而非 HTTP

此外,请特别注意通过 HTTP 检索的资源。如果您的扩展程序用于 因此网络攻击者(也称为"man-in-the-middle")可以修改响应, 并有可能攻击您的扩展程序因此,请尽可能使用 HTTPS。

调整内容安全政策

如果您通过添加 content_security_policy属性添加到清单中,则需要确保 允许您想要连接的买方。虽然默认政策不限制与主机的连接 在明确添加 connect-srcdefault-src 指令时,请务必小心谨慎。