Implementando Content Security Policy en el blog (WordPress)

por | noviembre 23, 2017

Content-Security-Policy (CSP) no es más que un header más (como X-XSS-Protection o X-Frame-Options) que ayuda a mejorar la seguridad de nuestro sitio web. Básicamente con CSP especificamos qué origen puede tener cada tipo de recurso servido en nuestra página.

CSP divide los tipos de recursos que puede cargar una web con una serie de directivas: default-src (por defecto), img-src (imágenes), font-src (fuentes), style-src (estilos), script-src (scripts), etc… en cada directiva especificamos el posible origen del recurso. Un ejemplo en Apache para un blog WordPress:

Header set Content-Security-Policy \
"default-src 'self' *.github.com *.wordpress.org secure.gravatar.com w.org s.w.org;\
 font-src 'self' 'unsafe-inline' data: *.googleapis.com fonts.gstatic.com;\
 style-src 'self' 'unsafe-inline' data: *.googleapis.com assets-cdn.github.com;\
 media-src 'self' *.youtube-nocookie.com;\
 frame-src 'self' *.youtube-nocookie.com;"

Un ejemplo en Nginx:

add_header Content-Security-Policy \
"script-src 'self' 'unsafe-inline' 'unsafe-eval' *.youtube.com *.googleapis.com *.google-analytics.com;\
 frame-src 'self' *.youtube.com;\
 font-src 'self' https://themes.googleusercontent.com;\ 
 object-src 'self'";

Si especificamos recursos con una directiva dedicada ésta tiene prevalencia sobre default-src. Por ejemplo, si ponemos una directiva font-src, el origen de dichos recursos será el especificado (en este caso 'self' 'unsafe-inline' data: *.googleapis.com fonts.gstatic.com) y no default-src. Por el contrario, como no he incluído en mi política img-src en este caso aplicará de forma genérica default-src para las imágenes de mi web. Todas las directivas disponibles podéis encontrarlas en la web de Mozilla aunque también tenemos esta web exclusivamente dedicada a CSP muy interesante.

¿Hasta qué punto tenemos que ser restrictivos con las directivas CSP? No es una ciencia exacta y depende del tipo de web y software que corramos detrás. A la hora de aplicar las directivas casi seguro que tendremos que hacer debug con nuestro navegador (F12 en Firefox/Chrome/Chromium) para ir ajustando las cabeceras según nuestras necesidades:

Podemos aplicar una política restrictiva no permitiendo nada por defecto e ir permitiendo exclusiones para cada recurso web:

Header set Content-Security-Policy \
"default-src 'none';\ 
 script-src 'self';\ 
 connect-src 'self';\ 
 font-src 'self' fonts.googleapis.com;\ 
 img-src 'self';\
 style-src 'self';\ 
 frame-src 'self';" 

Existe no obstante un modo CSP estricto ya definido por Google y recomendado para entornos de producción:

Content-Security-Policy:
  object-src 'none';
  script-src 'nonce-{random}' 'unsafe-inline' 'unsafe-eval' 'strict-dynamic' https: http:;
  base-uri 'none';
  report-uri https://your-report-collector.example.com/

Ahora bien, para implementar esto es necesario que la capa de software también permita hacerlo de forma razonable. Por ejemplo, nuestros scripts deberían admitir el atributo nonce para que la directiva script-src funcionara correctamente. Por desgracia no siempre podemos ser todo lo estrictos que quisiéramos ya que el core del producto que estamos utilizando (por ejemplo WordPress) puede dejar de funcionar de forma correcta. Ya vimos en un caso similar cómo mod_security había mejorado bastante la compatibilidad con WordPress y Drupal ya que era bastante habitual que acabara dejando prácticamente inutilizables webs enteras en pro de la seguridad.

Un recurso de interés que nos ayudará a la hora de configurar CSP es cspvalidator.org, que nos permite comprobar las cabeceras CSP de un sitio web:

Por otro lado csp-evaluator analiza las directivas configuradas realizando sugerencias y resaltando errores de sintaxis:

Así que si os proponéis añadir cabeceras CSP en vuestra web, que sea despacio y con buena letra 🙂