¿Cómo realizar una solicitud de origen cruzado en un script de contenido (actualmente bloqueado por CORB a pesar de los encabezados CORS correctos)?

Resuelto Ceasar asked hace 5 años • 3 respuestas

Estoy desarrollando una extensión de Chrome que realiza solicitudes desde ciertos sitios web a una API que controlo. Hasta Chrome 73, la extensión funcionaba correctamente. Después de actualizar a Chrome 73, comencé a recibir el siguiente error:

El bloqueo de lectura de origen cruzado (CORB) bloqueó la respuesta de origen cruzado http://localhost:3000/api/users/1 con aplicación/json de tipo MIME

Según la documentación de Chrome sobre CORB , CORB bloqueará la respuesta de una solicitud si se cumple todo lo siguiente:

  1. El recurso es un "recurso de datos". Específicamente, el tipo de contenido es HTML, XML, JSON.

  2. El servidor responde con un X-Content-Type-Options: nosniffencabezado o, si este encabezado se omite, Chrome detecta que el tipo de contenido es HTML, XML o JSON al inspeccionar el archivo.

  3. CORS no permite explícitamente el acceso al recurso

Además, según "Lessons from Spectre and Meltdown" (Google I/O 2018) , parece que puede ser importante agregar mode: corsinvocaciones fetch, es decir, fetch(url, { mode: 'cors' }).

Para intentar solucionar este problema, hice los siguientes cambios:

Primero, agregué los siguientes encabezados a todas las respuestas de mi API:

Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: Content-Type
Access-Control-Allow-Methods: GET, POST
Access-Control-Allow-Origin: https://www.example.com

En segundo lugar, actualicé mi fetch()invocación en la extensión para que se vea así:

fetch(url, { credentials: 'include', mode: 'cors' })

Sin embargo, estos cambios no funcionaron. ¿Qué puedo cambiar para que CORB no bloquee mi solicitud?

Ceasar avatar Mar 18 '19 12:03 Ceasar
Aceptado

Según los ejemplos de "Cambios en solicitudes de origen cruzado en scripts de contenido de extensión de Chrome" , reemplacé todas las invocaciones de fetchcon un nuevo método fetchResource, que tiene una API similar, pero delega la fetchllamada a la página en segundo plano:

// contentScript.js
function fetchResource(input, init) {
  return new Promise((resolve, reject) => {
    chrome.runtime.sendMessage({input, init}, messageResponse => {
      const [response, error] = messageResponse;
      if (response === null) {
        reject(error);
      } else {
        // Use undefined on a 204 - No Content
        const body = response.body ? new Blob([response.body]) : undefined;
        resolve(new Response(body, {
          status: response.status,
          statusText: response.statusText,
        }));
      }
    });
  });
}

// background.js
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
  fetch(request.input, request.init).then(function(response) {
    return response.text().then(function(text) {
      sendResponse([{
        body: text,
        status: response.status,
        statusText: response.statusText,
      }, null]);
    });
  }, function(error) {
    sendResponse([null, error]);
  });
  return true;
});

Este es el conjunto de cambios más pequeño que pude realizar en mi aplicación y que soluciona el problema. (Tenga en cuenta que las extensiones y las páginas en segundo plano solo pueden pasar objetos serializables JSON entre ellas, por lo que no podemos simplemente pasar el objeto Fetch API Response de la página en segundo plano a la extensión).

Las páginas en segundo plano no se ven afectadas por CORS o CORB, por lo que el navegador ya no bloquea las respuestas de la API.

¡Advertencia! La URL debe agregarse en manifest.json :

  • Para ManifestV3 en"host_permissions": ["*://*.example.com/"]
  • Para ManifestV2 en"permissions": ["*://*.example.com/"]
Ceasar avatar Mar 18 '2019 06:03 Ceasar

Consulte https://www.chromium.org/Home/chromium-security/extension-content-script-fetches

Para mejorar la seguridad, las recuperaciones de orígenes cruzados de secuencias de comandos de contenido no están permitidas en las extensiones de Chrome desde Chrome 85. En su lugar, dichas solicitudes se pueden realizar desde la secuencia de comandos en segundo plano de la extensión y se retransmiten a las secuencias de comandos de contenido cuando sea necesario.

Puedes hacer eso para evitar el origen cruzado.

Script de contenido antiguo, realizando una búsqueda de origen cruzado:

var itemId = 12345;
var url = "https://another-site.com/price-query?itemId=" +
         encodeURIComponent(request.itemId);
fetch(url)
  .then(response => response.text())
  .then(text => parsePrice(text))
  .then(price => ...)
  .catch(error => ...)

Nuevo script de contenido, que solicita a su página de fondo que recupere los datos:

chrome.runtime.sendMessage(
    {contentScriptQuery: "queryPrice", itemId: 12345},
    price => ...);

Nueva página de fondo de extensión, que se obtiene de una URL conocida y transmite datos:

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

Permitir la URL en manifest.json ( más información ):

  • ManifiestoV2 (clásico):"permissions": ["https://another-site.com/"]
  • ManifestV3 ( próximo ):"host_permissions": ["https://another-site.com/"]
李方郑 avatar Mar 22 '2019 02:03 李方郑