Implementando Política de Seguridad de Contenido (CSP)

14 abril, 2016 3:29 por

Esta es una traducción del artículo original publicado en el blog de Mozilla Hacks.

El equipo de complementos recientemente completó el trabajo de habilitar la Política de Seguridad de Contenido (CSP) en addons.mozilla.org (AMO). Este artículo está pensado para cubrir lo básico en implementar CSP, así como resaltar algunos de los problemas que encontramos implementando CSP en AMO.

¿Qué es CSP?

CSP es un estándar de seguridad creado para ayudar a prevenir cross-site scripting (XSS) y otros tipos de ataques de inyección de contenido. Ésto se logra restringiendo las fuentes de contenido cargadas por el navegador a aquellas solamente permitidas por el operador del sitio.

La política se implementa por medio de encabezados que son enviados con la respuesta del servidor. A partir de ahí, depende de los navegadores el tomar esa política y bloquear las violaciones a la misma que sean detectadas.

¿Por qué se necesita?

CSP es otra capa de defensa para ayudar a proteger a los usuarios de una variedad de ataques como XSS y otras formas de inyecciones. Mientras no es una bala de plata, permite hacer considerablemente más difícil para un atacante inyectar contenido y extraer datos.

Crear páginas web seguras es difícil. Incluso si sabes las mejores prácticas de seguridad, sigue siendo increíblemente fácil pasar por alto algo, o sin querer hacer un agujero de seguridad en un sitio web que es de otra manera seguro.

El CSP trabaja restringiendo los orígenes de los contenidos activos y pasivos de que pueden ser cargados. Adicionalmente puede restringir ciertos aspectos de contenido activo, como la ejecución en linea de JavaScript y el uso de eval().

Implementando CSP

Para implementar CSP, debes definir una lista de orígenes conocidos y permitidos para cada uno de los recursos que usas en tu sitio web. Por ejemplo, si tienes un sitio simple que necesita cargar scripts, hojas de estilo, e imágenes hosteadas localmente así como desde la librería jQuery desde su CDN, podrías usar also así:

Content-Security-Policy:
    default-src 'self';
    script-src 'self' https://code.jquery.com;

En el ejemplo de arriba, Content-Security-Policy es la cabecera HTTP. También puedes especificar Content-Security-Policy-Report-Only, lo que quiere decir que el navegador va a reportar errores, pero no va a bloquear nada activamente. Mientras estás probando la nueva política, esta es una característica bastante útil de utilizar.

Para script-src, debemos tener que explícitamente listar 'self' Porque si no defines ninguna directiva entonces no va a heredar desde default-src.

Es muy importante que siempre definas default-src. De otra manera las directivas van a permitir todos los recursos. Porque tenemos default-src 'self', quiere decir que las imágenes servidas desde el dominio del sitio serán permitidas.

default-src es una directiva especial que utilizarán las directivas de fuentes si no son configuradas. Sin embargo, las siguientes directivas no heredan de default-src, así que ten presente esto y recuerda que si no colocas configuración, quiere decir que la configuración no tendrá un valor definido o usará la configuración por defecto del navegador:

  • base-uri
  • form-action
  • frame-ancestors
  • plugin-types
  • report-uri
  • sandbox

Configurando 'self' como default-src es generalmente seguro, porque controlas tu propio dominio. Sin embargo, si quieres mantener todo muy seguro por defecto, puedes usar default-src 'none'y explícitamente listar todos los recursos conocidos. Dado el ejemplo anterior, esto resultaría en una política como ésta:

Content-Security-Policy:
    default-src 'none';
    img-src 'self';
    script-src 'self' https://code.jquery.com;
    style-src 'self';

Si dependes del prefetching (carga previa), puedes encontrar problemas con default-src 'none'. En AMO descubrimos que el prefetching en Firefox no identifica el tipo de contenido, así que recae en default-src. Si default-src no cubre los orígenes involucrados, el recurso será bloqueado. Hay un bug abierto con información adicional referente a este problema.

Manejando los scripts en línea

CSP por defecto no permite scripts en línea, a menos que explícitamente lo permitas. Esto quiere decir que tienes que remover lo siguiente:

  • Los bloques <script> en la pagina
  • Los manejadores de eventos DOM en HTML ej: onclick
  • Pseudo-protocolo javascript:

Si necesitas permitirlos entonces el CSP provee una manera de hacerlo de forma segura por medio del uso de las directivas nonce-source o hash-source, lo cual permite específicamente los bloques de contenido que pueden ser ejecutados. También puedes desactivarlo usando ‘unsafe-inline’ en la directiva script-src, pero esto no es recomendado, porque te deja vulnerable a ataques XSS.

Para información adicional al nonce-source y hash-source, puedes leer CSP for the web we have.

Manejando el eval()

CSP también bloquea scripts dinámicos que ejecutan algo, como

  • eval()
  • Una cadena usada como primer argumento para fijar setTimeout / setInterval
  • El constructor new Function()

Si necesitas permitir esto, puedes usar 'unsafe-eval' pero de nuevo esto no es recomendado porque permite que fácilmente código no confiable se escurra a un bloque de eval.

En AMO, encontramos muchísimos códigos en librerías que usan eval y new Function, y ésta fue la parte de la implementación del CSP que tomá más tiempo arreglar. Por ejemplo, teníamos plantillas de underscore que usaban new Function. Arreglar eso requirió movernos a plantillas pre-compiladas.

Manejando las hojas de estilo (CSS)

CSP por defecto no permite:

  • Bloques <style>
  • Atributos HTML style

Esto fue un poco más problemático para nosotros. Muchas librerías usan atributos style en fragmentos de código HTML agregados a la página mediante JavaScript, y teníamos una serie de atributos style esparcidos directamente en las plantillas HTML.

Cabe mencionar que si los estilos son cargados via JavaScript directamente, entonces no tienes problemas. Por ejemplo, el método css()  de jQuery, esta bien ya que actualiza el estilo directamente. Sin embargo no puedes usar style="background: red" en un bloque HTML agregado por JS.

Esto puede ser un poco confuso, porque en el inspector de Firefox, las propiedades de estilos agregadas por JavaScript parecen iguales a los atributos de estilo en HTML.

Como en los casos anteriores, puedes usar el nonce-source y hash-source si necesitas un acercamiento controlado para permitir piezas de CSS en línea.

Quizás pienses, «Esto es CSS, cual es el riesgo?». Hay varias maneras ingeniosas en que el CSS puede ser usado para sacar información del sitio web, por ejemplo, con los atributos de selectores e imágenes de fondo, puedes hacer un ataque de fuerza bruta, y sacar información sensible como tokens CSRF. Para más información de este u otros métodos de ataque avanzados por medio del CSS puedes leer XSS (No, the _other ‘S’).

Usar 'unsafe-inline' para style-src no es recomendado, pero es un caso de balancear el riesgo contra el número de cambios necesarios para eliminar los estilos en línea.

Reportes

Es una buena idea poner la directiva report-uri y seleccionar un sitio donde se recolecte los reportes en formato JSON de las violaciones CSP. Como CSP no maneja aún la agrupación de errores, una sola página con múltiples errores enviará múltiples errores a tu punto de entrega de errores. Si manejas un sitio con mucha audiencia, ese punto de entrega puede recibir una gran cantidad de tráfico.

Adicionalmente de los reportes activados por verdaderas violaciones, también te encontrarás con muchos complementos que causan violaciones CSP. El resultado es que generara mucho ruido: tener algo que permita filtrar los datos es altamente recomendable.

Probando

Una vez que hayas creado tu política inicial, el siguiente paso es ir probando y corrigiendo los orígenes que faltan. Si manejas un sitio grande, te sorprenderá el número de recursos que sacas de otras fuentes. Correr el sitio con CSP en modo de solo reportes te ayuda a atrapar errores vía la consola y los reportes de CSP, antes de realmente bloquear cosas.

Una vez que se haya verificado que todo funcione, y no se bloquee nada erróneamente, es hora de activar la política. Desde aquí en adelante solo es cuestión de mirar si algo falta, y mantener la política actualizada con nuevas funciones de los navegadores.

Implementando

Luego de que te asegures que la política funcione correctamente, el siguiente paso es configurar tu sistema para manejar directivas CSP. Implementar esto depende de tus configuraciones en el software del servidor. Pero debería verse algo así:

# Habilitar CSP en Apache
Header set Content-Security-Policy "default-src 'none'; img-src 'self';
    script-src 'self' https://code.jquery.com; style-src 'self'"
# Habilitar CSP en nginx
add_header Content-Security-Policy "default-src 'none'; img-src 'self';
    script-src 'self' https://code.jquery.com; style-src 'self'";

Si tu proveedor de servicios no te permite manejar la configuración del servidor, ¡no te alarmes! Puedes usarlo desde el tag meta. Simplemente coloca tu meta<head>:



    

Nuestra implementación final

Dado que AMO es un sitio más viejo y extremadamente complejo, probablemente tienes curiosidad de cómo terminó nuestra política:

Content-Security-Policy:
    default-src 'self';
    connect-src 'self' https://sentry.prod.mozaws.net;
    font-src 'self' https://addons.cdn.mozilla.net;
    frame-src 'self' https://ic.paypal.com https://paypal.com
        https://www.google.com/recaptcha/ https://www.paypal.com;
    img-src 'self' data: blob: https://www.paypal.com https://ssl.google-analytics.com
        https://addons.cdn.mozilla.net https://static.addons.mozilla.net
        https://ssl.gstatic.com/ https://sentry.prod.mozaws.net;
    media-src https://videos.cdn.mozilla.net;
    object-src 'none';
    script-src 'self' https://addons.mozilla.org
        https://www.paypalobjects.com https://apis.google.com
        https://www.google.com/recaptcha/ https://www.gstatic.com/recaptcha/
        https://ssl.google-analytics.com https://addons.cdn.mozilla.net;
    style-src 'self' 'unsafe-inline' https://addons.cdn.mozilla.net;
    report-uri /__cspreport__

¡Wow! Como te puedes imaginar, son muchos tests los que ayudaron a descubrir todos los recursos que usa AMO.

En resumen

Mientras más viejo sea tu sitio, más trabajo tendrás para colocar y adherir una política de seguridad razonable. Sin embargo, el tiempo que te toma vale la pena, porque agregas una capa más de seguridad que soporta la idea de la defensa en profundidad.

Lectura adicional

The following two tabs change content below.
Si, mi biografia esta vacia. 🙂

Compartir artículo:

Empezar la discusión en foro.mozilla-hispano.org

  • ¡Participa!

    Firefox Friends »
    Agrega botones de Firefox en tu sitio web y comparte tu amor por Mozilla Firefox.
    Ayuda a otros usuarios en Twitter.
    Colabora con la comunidad »
    En Mozilla lo importante son las personas. Descubre cómo puedes colaborar.

    Boletín Firefox

    Suscríbete al boletín de novedades de Firefox.

  • Descargas

    Descarga los programas de Mozilla.

    Lo más visto

    cc-by-sa