Compartir vía


Uso de la directiva de seguridad de contenido (CSP) para controlar qué recursos se pueden ejecutar

Para controlar qué contenido puede ejecutar la extensión, en el archivo de manifest.json la extensión, use la content_security_policy clave y su valor de cadena de directiva, según la sintaxis siguiente:

{
    ...,
    "content_security_policy": "[policy string]"
    ...
}

Por ejemplo, la siguiente es la directiva de seguridad de contenido predeterminada, como se describe a continuación en Restricciones de directivas predeterminadas:

{
    ...,
    "content_security_policy": "script-src 'self'; object-src 'self'; worker-src 'self'"
    ...
}

Para mitigar una gran clase de posibles problemas de scripting entre sitios, el sistema de extensiones de Microsoft Edge incorpora la directiva de seguridad de contenido (CSP). CSP presenta algunas directivas estrictas que hacen que las extensiones sean más seguras de forma predeterminada y le proporciona la capacidad de crear y aplicar reglas que rigen los tipos de contenido que las extensiones y las aplicaciones pueden cargar y ejecutar.

En general, CSP funciona como un mecanismo de inclusión en bloques o permitidos para los recursos cargados o ejecutados por la extensión. La definición de una directiva razonable para la extensión le permite tener en cuenta cuidadosamente los recursos que requiere la extensión y pedir al explorador que asegúrese de que esos son los únicos recursos a los que tiene acceso la extensión. Las directivas proporcionan seguridad sobre los permisos de host que solicita la extensión; son una capa adicional de protección, no un reemplazo.

Por el contrario, en una página web, dicha directiva se define a través de un encabezado HTTP o a través de un meta elemento . Pero dentro del sistema de extensiones de Microsoft Edge, un encabezado HTTP o un meta elemento no es un mecanismo adecuado.

Vea:

Restricciones de directiva predeterminadas

Los paquetes que no definen un manifest_version no tienen una directiva de seguridad de contenido predeterminada.

Los paquetes que usan manifest_version tienen la siguiente directiva de seguridad de contenido predeterminada:

script-src 'self'; object-src 'self'; worker-src 'self'

La directiva agrega seguridad limitando las extensiones y las aplicaciones de tres maneras:

El código como el siguiente no funciona:

alert(eval("foo.bar.baz"));
window.setTimeout("alert('hi')", 10);
window.setInterval("alert('hi')", 10);
new Function("return foo.bar.baz");

La evaluación de cadenas de JavaScript como esta es un vector de ataque XSS común. En su lugar, debe escribir código como:

alert(foo && foo.bar && foo.bar.baz);
window.setTimeout(function() { alert('hi'); }, 10);
window.setInterval(function() { alert('hi'); }, 10);
function() { return foo && foo.bar && foo.bar.baz };

JavaScript insertado no se ejecuta

JavaScript insertado no se ejecuta. Esta restricción prohíbe tanto los bloques insertados <script> como los controladores de eventos insertados, como <button onclick="...">.

La primera restricción elimina una enorme clase de ataques de scripting entre sitios al hacer que sea imposible ejecutar accidentalmente el script proporcionado por un tercero malintencionado. Sin embargo, es necesario escribir el código con una separación limpia entre el contenido y el comportamiento. Un ejemplo podría hacer que esto sea más claro. Podría intentar escribir un elemento emergente Acción del explorador como un único pop-up.html que contenga lo siguiente:

<!doctype html>
<html>
    <head>
        <title>My Awesome Pop-up!</title>
        <script>
            function awesome() {
                // do something awesome!
            }

            function totallyAwesome() {
                // do something TOTALLY awesome!
            }

            function clickHandler(element) {
                setTimeout("awesome(); totallyAwesome()", 1000);
            }

            function main() {
                // Initialization work goes here.
            }
        </script>
    </head>
    <body onload="main();">
        <button onclick="clickHandler(this)">
            Click for awesomeness!
        </button>
    </body>
</html>

Pero tres cosas deben cambiar para que esto funcione de la manera que espera:

  • La clickHandler definición debe moverse a un archivo JavaScript externo (popup.js puede ser un buen destino).

  • Las definiciones del controlador de eventos insertados deben volver a escribirse en términos de addEventListener y extraerse en popup.js. Si actualmente está iniciando el programa con código como <body onload="main();">, considere la posibilidad de reemplazarlo enlazando al DOMContentLoaded evento del documento o al load evento de la ventana, en función de sus requisitos. Use el primero, ya que generalmente se desencadena más rápidamente.

  • La setTimeout llamada debe volver a escribirse para evitar convertir la cadena "awesome(); totallyAwesome()" en JavaScript para su ejecución.

Estos cambios podrían tener un aspecto similar al siguiente:

function awesome() {
    // Do something awesome!
}

function totallyAwesome() {
    // do something TOTALLY awesome!
}

function awesomeTask() {
    awesome();
    totallyAwesome();
}

function clickHandler(e) {
    setTimeout(awesomeTask, 1000);
}

function main() {
    // Initialization work goes here.
}

// Add event listeners once the DOM has fully loaded by listening for the
// `DOMContentLoaded` event on the document, and adding your listeners to
// specific elements when it triggers.
document.addEventListener('DOMContentLoaded', function () {
    document.querySelector('button').addEventListener('click', clickHandler);
    main();
});
<!doctype html>
<html>
    <head>
        <title>My Awesome Pop-up!</title>
        <script src="popup.js"></script>
    </head>
    <body>
        <button>Click for awesomeness!</button>
    </body>
</html>

Solo se cargan los recursos de script y objeto locales

Los recursos de script y objeto solo se pueden cargar desde el paquete de extensión, no desde la web en general. Esto garantiza que la extensión solo ejecuta el código que aprobó específicamente, lo que impide que un atacante de red activo redirija de forma malintencionada la solicitud de un recurso.

En lugar de escribir código que dependa de la carga de jQuery (o de cualquier otra biblioteca) desde una red CDN externa, considere la posibilidad de incluir la versión específica de jQuery en el paquete de extensión. Es decir, en lugar de:

<!doctype html>
<html>
    <head>
        <title>My Awesome Pop-up!</title>
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
    </head>
    <body>
        <button>Click for awesomeness!</button>
    </body>
</html>

En su lugar, use el siguiente enfoque. Descargue el archivo, inscríbelo en el paquete y escriba lo siguiente:

<!doctype html>
<html>
    <head>
        <title>My Awesome Pop-up!</title>
        <script src="jquery.min.js"></script>
    </head>
    <body>
        <button>Click for awesomeness!</button>
    </body>
</html>

Relajación de la directiva predeterminada

Puede permitir la ejecución de los siguientes tipos de script:

A continuación se detallan los detalles.

Script insertado

Los scripts insertados se pueden permitir especificando el hash codificado en base64 del código fuente en la directiva. Este hash debe ir precedido por el algoritmo hash usado (sha256, sha384 o sha512). Para obtener un ejemplo, vea Uso de hash W3C > para <elementos de script>.

Script remoto

Si necesita algunos recursos de objetos o JavaScript externos, puede relajar la directiva en una medida limitada mediante la inclusión en la lista de permitidos de orígenes seguros a partir de los cuales se deben aceptar scripts. Compruebe que los recursos en tiempo de ejecución cargados con permisos elevados de una extensión son exactamente los recursos que espera y que no se reemplazan por un atacante de red activo. Dado que los ataques man-in-the-middle son triviales e indetectables a través de HTTP, esos orígenes no se aceptan.

Actualmente, puede permitir la lista de orígenes que tienen los siguientes esquemas: blob, filesystem, httpsy extension. La parte host del origen debe especificarse explícitamente para los https esquemas y extension . Los caracteres comodín genéricos, como https:, https://* y https://*.com no se permiten; se permiten caracteres comodín de subdominio, como https://*.example.com . Los dominios de la lista Sufijo público también se ven como dominios genéricos de nivel superior. Para cargar un recurso desde estos dominios, el subdominio debe aparecer explícitamente. Por ejemplo, https://*.cloudfront.net no es válido, pero https://XXXX.cloudfront.net puede https://*.XXXX.cloudfront.net ser allowlisted.

Para facilitar el desarrollo, los recursos cargados a través de HTTP desde servidores de la máquina local pueden ser allowlisted. Puede permitir la lista de scripts y orígenes de objetos en cualquier puerto de o http://127.0.0.1http://localhost.

Nota:

La restricción de los recursos cargados a través de HTTP solo se aplica a los recursos que se ejecutan directamente. Sigue siendo libre, por ejemplo, para realizar XMLHTTPRequest conexiones a cualquier origen que desee; la directiva predeterminada no restringe connect-src ni ninguna de las demás directivas csp de ninguna manera.

Una definición de directiva relajada que permite cargar recursos de script desde a través de example.com HTTPS puede tener el siguiente aspecto:

"content_security_policy": "script-src 'self' https://example.com; object-src 'self'"

Nota:

Tanto como script-srcobject-src están definidos por la directiva. Microsoft Edge no acepta una directiva que no limite cada uno de estos valores a (al menos) ""self.

JavaScript evaluado

La directiva en eval() y las funciones relacionadas como setTimeout(String), setInterval(String)y new Function(String) se pueden relajar agregando unsafe-eval a la directiva:

"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'"

Sin embargo, debe evitar las directivas relajantes. Estos tipos de funciones son vectores de ataque XSS notorios.

Ajuste de la directiva predeterminada

Puede ajustar esta directiva en cualquier medida que la extensión permita, con el fin de aumentar la seguridad, a costa de la comodidad. Para especificar que la extensión solo puede cargar recursos de cualquier tipo (imágenes, etc.) desde el paquete de extensión asociado, por ejemplo, una directiva de default-src 'self' puede ser adecuada.

Scripts de contenido

La directiva que se está analizando se aplica a las páginas en segundo plano y a las páginas de eventos de la extensión. La forma en que los scripts de contenido se aplican a los scripts de contenido de la extensión es más complicada.

Por lo general, los scripts de contenido no están sujetos al CSP de la extensión. Dado que los scripts de contenido no son HTML, el impacto principal de esto es que pueden usar eval incluso si el CSP de la extensión no especifica unsafe-eval, aunque no se recomienda. Además, el CSP de la página no se aplica a los scripts de contenido. Más complicadas son <script> las etiquetas que los scripts de contenido crean y colocan en el DOM de la página en la que se ejecutan. Se hace referencia a ellos como scripts insertados dom en el futuro.

DOM ha insertado scripts que se ejecutan inmediatamente después de la inserción en la página que se ejecutan como cabría esperar. Imagine un script de contenido con el código siguiente como un ejemplo sencillo:

document.write("<script>alert(1);</script>");

Este script de contenido provoca un alert inmediatamente después de document.write(). Tenga en cuenta que esto se ejecuta independientemente de la directiva que especifique una página. Sin embargo, el comportamiento se vuelve más complicado tanto dentro de ese script insertado dom como para cualquier script que no se ejecute inmediatamente tras la inyección.

Imagine que la extensión se ejecuta en una página que proporciona un CSP asociado que especifica script-src 'self'. Ahora imagine que el script de contenido ejecuta el código siguiente:

document.write("<button onclick='alert(1);'>click me</button>'");

Si un usuario hace clic en ese botón, el onclick script no se ejecuta. Esto se debe a que el script no se ejecutó inmediatamente y el código que no se interpreta hasta que se produce el click evento no se considera parte del script de contenido, por lo que el CSP de la página (no de la extensión) restringe el comportamiento. Y como ese CSP no especifica unsafe-inline, se bloquea el controlador de eventos insertados.

La manera correcta de implementar el comportamiento deseado en este caso es agregar el onclick controlador como una función desde el script de contenido, como se indica a continuación:

document.write("<button id='mybutton'>click me</button>'");
var button = document.getElementById('mybutton');
button.onclick = function() {
      alert(1);
};

Otro problema similar surge si el script de contenido ejecuta lo siguiente:

var script = document.createElement('script');
script.innerHTML = 'alert(1);'
document.getElementById('body').appendChild(script);

En este caso, se ejecuta el script y aparece la alerta. Sin embargo, tenga en cuenta este caso:

var script = document.createElement('script');
script.innerHTML = 'eval("alert(1);")';
=document.getElementById('body').appendChild(script);

Mientras se ejecuta el script inicial, la llamada a eval se bloquea. Es decir, mientras se permite el tiempo de ejecución del script inicial, el comportamiento dentro del script está regulado por el CSP de la página. Por lo tanto, en función de cómo escriba scripts insertados dom en la extensión, los cambios en el CSP de la página pueden afectar al comportamiento de la extensión.

Dado que los scripts de contenido no se ven afectados por el CSP de la página, esta es una excelente razón para colocar el mayor comportamiento posible de la extensión en el script de contenido, en lugar de los scripts insertados por DOM.

Recursos adicionales

Nota:

Las partes de esta página son modificaciones basadas en el trabajo creado y compartido por Google y usadas según los términos descritos en la licencia internacional creative Commons Attribution 4.0. La página original se encuentra aquí.

Licencia de Creative Commons Esta obra está licenciada bajo una Licencia Internacional Creative Commons Attribution 4.0.