Políticas sencillas de seguridad de contenidos para defenderse de los ataques XSS

 

En las últimas semanas hemos cubierto en el blog bastantes cabeceras HTTP relacionadas con la seguridad, pero la jefa de todas ellas tiene que ser Content-Security-Policy(CSP). El jefe, tanto por el nivel de protección que proporciona como, desgraciadamente, por la dificultad de implementarlo correctamente a la primera. Como con todas las reglas de gestión del tráfico flightPATH de las que hemos hablado recientemente, las utilizamos nosotros mismos para proteger el sitio web edgeNEXUS y a sus visitantes.

Hemos hecho el trabajo duro y hemos sentido el dolor para que tú no tengas que hacerlo, pero es innegable que hay que pensar y planificar antes de ponerlo en práctica. Pero merece la pena. El concepto de esta cabecera es bastante sencillo e igual de potente. En pocas palabras, se utiliza para especificar los orígenes permitidos del contenido que se puede cargar en tu sitio web. Esto proporciona una fuerte protección contra una serie de ataques de inyección de código frecuentes en la cada vez más dinámica Internet de hoy en día, como el Cross Site Scripting (XSS) y el Clickjacking.

Los tipos de contenido que se pueden controlar son: JavaScript, CSS (sí, el CSS puede ser peligroso), marcos HTML, fuentes, imágenes y objetos incrustables como los applets de Java. Es estupendo tener tantas opciones, pero aquí es donde surge la dificultad. Los sitios web actuales (incluidos los nuestros) contienen una multitud de estos tipos de contenido de muchas fuentes, e identificarlos y tenerlos en cuenta en una política puede ser todo un esfuerzo.

Antes de entrar en materia, echemos un vistazo a los elementos del valor de la cabecera y al aspecto de una política. Como verás, se trata esencialmente de una larga lista de tipos de contenido (todos terminan con -src en este ejemplo) y las fuentes permitidas para cada tipo. En conjunto, se conocen como directivas de política.

default-src “self” data:; script-src “self” “unsafe-inline”; connect-src “self”; img-src “self” data:; style-src “self” “unsafe-inline” data:; font-src “self” data:; child-src “self”

Hay más tipos de contenido que podemos tener en cuenta, pero las que se muestran arriba son las directivas más importantes (en nuestra opinión, basadas en el riesgo y la prevalencia). A continuación se detalla a qué contenido se refiere cada una;

  • default-src – Valores por defecto para la mayoría de los tipos de contenido (pero no todos) si no se especifican después
  • script-src – Fuentes permitidas para scripts (incluido JavaScript)
  • connect-src – Fuentes permitidas para las conexiones (como WebSockets y EventSource utilizados, por ejemplo, con aplicaciones de chat)
  • img-src – Fuentes permitidas para las imágenes
  • style-src – Fuentes permitidas para CSS
  • font-src – Fuentes permitidas para las fuentes
  • child-src – Fuentes permitidas para marcos e iframes

Estos tipos de contenido y sus valores están separados entre sí (delimitados) por un punto y coma. Cada tipo puede tener uno o varios de los siguientes valores;

  • ninguno» – no permitir este tipo de contenido
  • auto» – permite este tipo de contenido si se origina directamente en este sitio (pero no en subdominios)
  • “unsafe-inline” – permitir CSS y JavaScript inline (por desgracia, es muy común)
  • datos: – permiten fuentes de datos en línea (normalmente se utilizan para proporcionar fuentes e imágenes en línea para mejorar el rendimiento)
  • https: – sólo permitir este tipo de contenido a través de HTTPS
  • “unsafe-eval” – permite analizar el texto utilizando métodos potencialmente peligrosos que pueden provocar la ejecución de código
  • nombre-dominio – permite este tipo de contenido si se origina en el nombre-dominio especificado (en otras palabras, un dominio remoto) – puede utilizarse varias veces
  • * – cualquier dominio

Se utiliza un espacio simple para delimitar cada valor. Las comillas simples ‘ son necesarias a menos que el valor sea un nombre de dominio. Ten en cuenta que las extensiones del navegador y los plugins están exentos, ya que se consideran seguros porque el usuario confía en ellos (al fin y al cabo, es quien los ha instalado).

Todo parece bastante técnico y complejo, pero si lo abordamos paso a paso es bastante rápido llegar a una política. Vamos a trabajar rápidamente con dos ejemplos. En primer lugar, probemos con un simple sitio web interno servido a través de HTTP. Esto es lo que necesitamos

  • default-src “datos propios”: – permitir sólo contenido de nuestro propio sitio, incluyendo objetos inline
  • script-src “self” “unsafe-inline” – permitir scripts de nuestro propio sitio, incluidos los inline
  • connect-src “self” – permitir conexiones desde/a nuestro propio sitio
  • datos img-src “self”: – permitir imágenes de nuestro propio sitio, incluidas las inline
  • style-src “self” “unsafe-inline” data: – permitir CSS de nuestro propio sitio, incluyendo estilos inline
  • datos font-src “self”: – permitir fuentes de nuestro propio sitio, incluidas las inline

El valor completo de la cabecera es razonablemente corto:

default-src “self” data:; script-src “self” “unsafe-inline”; connect-src “self”; img-src “self” data:; style-src “self” “unsafe-inline” data:; font-src “self” data:

En segundo lugar, un sitio web de cara a Internet protegido por SSL/TLS que utiliza Google Analytics (GA), CSS en línea, fuentes e imágenes, CSS de tu sitio e imágenes de otros sitios web. Repasemos lo que necesitamos pieza por pieza (no es muy diferente);

  • default-src “self” data: https: – permitir contenido sólo de nuestro propio sitio, incluyendo objetos inline, sólo a través de HTTPS
  • script-src “self” “unsafe-inline” https: – permitir scripts de nuestro propio sitio, incluidos los inline, sólo a través de HTTPS
  • img-src “self” “unsafe-inline” \* https: – permite imágenes de cualquier sitio, incluidas las inline del nuestro, sólo a través de HTTPS
  • style-src “self” “unsafe-inline” https: – permitir CSS sólo de nuestro propio sitio, incluidos los inline, sólo a través de HTTPS
  • font-src “self” “unsafe-inline” https: – permitir sólo fuentes de nuestro propio sitio, incluidas las inline, sólo a través de HTTPS

Si lo sumamos todo, tenemos esta política ligeramente más larga:

default-src “self” data: https:; script-src “self” “unsafe-inline” *.google-analytics.com https:; img-src “self” “unsafe-inline” * https:; style-src “self” “unsafe-inline” https:; font-src “self” “unsafe-inline” https:

Yo diría que es bastante fácil. Google no era tan “amigable” con CSP en el pasado (este valor de cabecera solía ser al menos el doble de largo), pero afortunadamente han hecho grandes progresos recientemente. Verás que no hemos tenido que añadir el dominio *.google-analytics.com al script-src como valor de tipo de contenido, ya que su código se ejecuta como un script en línea.

Lo ideal sería que crearas una política por página de tu sitio web, ya que los recursos cargados sin duda variarán según la página, pero esto es bastante oneroso y es mucho más sencillo, aunque eficaz, crear una política que cubra todas las fuentes posibles. La mayoría de los ejemplos de nuestra página de GitHub adoptan este enfoque, pero también hay uno allí por si quieres proporcionar una mayor protección a páginas concretas.

Para probar y solucionar problemas, te recomiendo encarecidamente que utilices las Herramientas para desarrolladores de Google Chrome. Ve al sitio en cuestión y pulsa F12, haz clic en Red, asegúrate de que la opción Desactivar caché está marcada y vuelve a cargar la página. Cualquier error aparecerá claramente resaltado. Al final de este blog hay una pantalla de lo que podrías ver si tu política está bloqueando unsafe-inline y utilizas Google Analytics; los mensajes de error son muy útiles.

Ajusta tu política según sea necesario y aclara y repite. Lo ideal sería que lo hicieras utilizando un Servicio Virtual de pruebas dedicado con la regla flightPATH que estás probando aplicada, pero que por lo demás sirviera al mismo sitio, sólo que a través de una IP Virtual diferente para no afectar a los clientes reales mientras realizas las pruebas.

Como siempre ocurre, la gran ventaja de utilizar un equilibrador de carga es que sólo tenemos que hacerlo en un lugar central para proteger todos nuestros servidores (y sitios). No necesitamos depender de desarrolladores ni de reconfiguraciones del servidor web. En el equilibrador de carga edgeNEXUS sólo tenemos que importar una plantilla de configuración automática jetPACK y asignar una regla de tráfico flightPATH al Servicio o Servicios Virtuales que deseemos proteger (tras las modificaciones oportunas).

La regla sólo añade la cabecera si no existe, por lo que funcionará incluso cuando nuestros servidores web ya la inserten o quizás sólo la inserten para páginas concretas. Esta regla debería formar parte de tu configuración estándar del Servicio Virtual: no tienes nada que perder sea cual sea el sitio aunque, por supuesto, siempre se recomienda hacer pruebas. Puedes descargar este jetPACK y muchos otros en el sitio Github de edgeNEXUS.

flightPATH es un motor de reglas dinámico y basado en eventos desarrollado por edgeNEXUS para manipular y enrutar de forma inteligente el tráfico IP, HTTP y HTTPS de carga equilibrada. Es altamente configurable y potente, pero muy fácil de usar.

Merece la pena leer estos enlaces relacionados si quieres saber más;

http://www.html5rocks.com/en/tutorials/security/content-security-policy/

https://developer.mozilla.org/en/docs/Web/Security/CSP/CSP_policy_directives

http://content-security-policy.com/

https://www.clickintelligence.co.uk/header-response-checker/

En las últimas semanas hemos cubierto en el blog bastantes cabeceras HTTP relacionadas con la seguridad, pero la jefa de todas ellas tiene que ser Content-Security-Policy (CSP).

About Donna Toomey