Los co­n­te­ni­dos activos en páginas web, como por ejemplo Ja­va­S­cri­pt, CSS o ActiveX, plantean riesgos de seguridad para los usuarios de Internet y los gestores de páginas web y pueden ma­ni­pu­lar­se, por ejemplo, mediante el Cross Site Scripting. Para que las páginas de Internet puedan uti­li­zar­se sin preo­cu­pa­cio­nes, existe lo que se conoce como Content Security Policy (CSP), cuyo papel consiste en proteger a las páginas frente a ataques pe­r­ju­di­cia­les y es co­m­pa­ti­ble con la mayoría de na­ve­ga­do­res web. Por ello, este concepto de seguridad protege tanto a páginas web como a usuarios de Internet, pero ¿en qué consiste y cómo funciona CSP?

De­sa­rro­llo de la Content Security Policy

La Política de seguridad de contenido (CSP, Content Security Policy) tiene sus orígenes en el año 2004, cuando se le conocía con el nombre de “Content Re­s­tri­c­tion”. Su aparición estuvo motivada por las brechas de seguridad cada vez mayores en los scripts de Internet. El Cross Site Scripting (XSS) en concreto es un método criminal que consiste en infiltrar código malicioso en una página web, por lo que plantea un enorme riesgo para los usuarios. Si bien los usuarios visitan una página en principio fiable, en ella puede haberse insertado un script que carga los datos ma­li­cio­sos de una fuente externa. Los ci­be­r­de­li­n­cue­n­tes utilizan para ello, por ejemplo, brechas de seguridad en las funciones de co­me­n­ta­rios de la página. Así pueden obtener acceso a or­de­na­do­res pe­r­so­na­les sin que los usuarios de Internet sean co­n­s­cie­n­tes de ello y en la mayoría de los casos, ni siquiera los we­b­ma­s­te­rs suelen darse cuenta de la in­fi­l­tra­ción de código.

La Mozilla Fou­n­da­tion impulsó el de­sa­rro­llo de la CSP para so­lu­cio­nar esta pro­ble­má­ti­ca. La ventaja del estándar de seguridad es que se pueden es­ta­ble­cer reglas en el navegador con respecto a los scripts que el software tiene que cargar y los que no. Para ello, la Content Security Policy se basa en cabeceras HTTP.

Hecho

La Mozilla Fou­n­da­tion es la or­ga­ni­za­ción que se encarga del de­sa­rro­llo del navegador Firefox. Esta or­ga­ni­za­ción no lucrativa se ocupa de es­tru­c­tu­rar los proyectos de Mozilla y de llevar a cabo in­no­va­cio­nes en Internet y fue fundada por los antiguos tra­ba­ja­do­res de Netscape, que de­sa­rro­lla­ron uno de los primeros na­ve­ga­do­res web.

¿Cómo funciona la Content Security Policy?

Para es­ta­ble­cer la co­mu­ni­ca­ción en Internet, cliente y servidor in­te­r­ca­m­bian datos a través del Hypertext Transfer Protocol (HTTP). Los campos de las cabeceras HTTP son una parte muy im­po­r­ta­n­te de las requests (pe­ti­cio­nes) y las responses (re­s­pue­s­tas) y en ellas se tra­n­s­mi­ten pa­rá­me­tros y ar­gu­me­n­tos re­le­va­n­tes para el in­te­r­ca­m­bio de ambos pa­r­ti­ci­pa­n­tes en la co­n­ve­r­sa­ción (servidor y cliente). Dichas cabeceras se dividen en diversos campos para so­li­ci­tu­des y re­s­pue­s­tas y pueden, por ejemplo, contener in­fo­r­ma­ción sobre el conjunto de ca­ra­c­te­res, el idioma y las cookies. CSP se de­sa­rro­lla como campo de cabecera de respuesta, lo que significa que el servidor entrega los datos y el navegador los procesa.

El webmaster crea la cabecera de la Content Security Policy y la integra en cada subpágina de la página web en la que deba aplicarse el estándar de seguridad. También cabe la po­si­bi­li­dad de aplicar di­fe­re­n­tes medidas de seguridad para cada una de las páginas. Un modo sencillo de im­ple­me­n­tar este concepto de seguridad es mediante la creación de archivos .htaccessd, que se colocan en las mismas carpetas (o en un nivel más elevado je­rá­r­qui­ca­me­n­te) que las páginas web o anclando la CSP di­re­c­ta­me­n­te en la co­n­fi­gu­ra­ción del servidor.

Nota

Si, como usuario de Internet quieres comprobar si tu navegador soporta una Content Security Policy, puedes realizar el CSP browser test. Este intenta cargar scripts e imágenes de fuentes externas (ino­fe­n­si­vas) y te muestra si el proceso se realiza con éxito. Si no carga fuentes externas, el navegador está seguro pues entiende y aplica la CSP.

En el marco de la Content Security Policy y para evitar el Cross Site Scripting, los we­b­ma­s­te­rs deben ex­te­r­na­li­zar todos los scripts en archivos separados en lugar de in­te­grar­los di­re­c­ta­me­n­te en el código fuente de la página web. La CSP funciona según el principio de la whitelist: en el header se mencionan las fuentes desde las que se pueden cargar scripts y datos. Si un script ajeno se introduce en el código HTML sin ser re­co­no­ci­do y este intenta cargar datos externos, el navegador del usuario lo impide. En general, una CSP bloquea todos los scripts que se en­cue­n­tran di­re­c­ta­me­n­te en el código (inline scripts). Con ello se protege tanto la página web como a los usuarios de Internet y sobre todo sus datos sensibles. 

La ma­ni­pu­la­ción mediante el Cross Site Scripting es para los ci­be­r­de­li­n­cue­n­tes algo muy sencillo de realizar. Casi todas las páginas de la World Wide Web tienen un campo de entrada de datos, como pueden ser los co­me­n­ta­rios, la barra de búsqueda o los campos de inicio de sesión. En ellos, en lugar de textos, también pueden in­se­r­tar­se scripts. Si el servidor no está protegido ade­cua­da­me­n­te, los cri­mi­na­les utilizan in­te­r­fa­ces de phishing, in­mo­vi­li­zan la página en su totalidad u obtienen el control del navegador web del usuario mediante software malicioso. La política de seguridad de contenido o, para ser más exactos, su campo en la cabecera, informa al navegador web sobre las fuentes desde las que puede cargar datos. Si se im­ple­me­n­ta esta política en el código de la página web, se responde al intento de acceder al código in­fi­l­tra­do mediante XSS con un mensaje de error.

Con la Content Security Policy los we­b­ma­s­te­rs también pueden hacer otras co­n­fi­gu­ra­cio­nes, por ejemplo, a través de las si­guie­n­tes di­re­c­ti­vas:

  • base-uri: limita los URL que pueden aparecer en el elemento <base> de la página web.  
  • child-src: establece las fuentes desde las que pueden aparecer datos en frames, como, por ejemplo, en los vídeos in­se­r­ta­dos por terceros.
  • connect-src: limita las fuentes con las que se puede vincular una página web, p. ej., a través de enlaces.
  • font-src: determina las fuentes desde las que se pueden cargar los tipos de letra.
  • form-action: facilita una lista de puntos finales válidos en fo­r­mu­la­rios. 
  • frame-ancestors: establece los dominios que pueden in­co­r­po­rar la página web como frames y iFrames.
  • img-src: restringe las fuentes desde las que se pueden cargar imágenes.
  • media-src: establece las fuentes a partir de las que se pueden cargar los formatos de audio y vídeo.
  • object-src: define los controles sobre Flash y otros plugins.
  • plugin-types: limita los tipos de plugins.
  • report-uri: es­pe­ci­fi­ca un URL al que se pueden enviar informes si se violan las medidas de seguridad.
  • script-src: define las fuentes pe­r­mi­ti­das para Ja­va­S­cri­pt.
  • style-src: funciona como script-src, pero se aplica a las hojas de estilo.
  • upgrade-insecure-requests: establece que las páginas inseguras deben tratarse con HTTP y HTTPS.
  • sandbox: desplaza la página co­rre­s­po­n­die­n­te a un sandbox (entorno de pruebas), en el que, se prohíben, entre otros, fo­r­mu­la­rios, ventanas eme­r­ge­n­tes y scripts.

Estas di­re­c­ti­vas solo se aplican si así se establece ex­pre­sa­me­n­te. En caso contrario pe­r­ma­ne­cen abiertas y re­pre­se­n­tan una brecha de seguridad, algo que se puede cambiar con default-src, que establece el estado por defecto de todas las di­re­c­ti­vas que terminan con -src. En lugar de dejarlas abiertas, podrías regular que solo se carguen datos de la propia página web, a menos que hayas definido una única página de otra forma en la cabecera HTTP. En algunas di­re­c­ti­vas es­pe­cia­les puedes agregar otras fuentes.

En el campo header pueden in­se­r­tar­se muchas di­re­c­ti­vas. Si quieres in­co­r­po­rar varias, puedes se­pa­rar­las con puntos y comas. Además, como webmaster debes es­pe­ci­fi­car todas las fuentes dentro de una directiva, pero no se permiten entradas múltiples de las mismas di­re­c­ti­vas con fuentes adi­cio­na­les como en el ejemplo siguiente:

script-src ejemplo1.local; script-src ejemplo2.local

En este solo es relevante la primera fuente, con lo que el cliente ignora la segunda. Por el contrario, se deben anotar ambas fuentes en una directiva:

script-src ejemplo1.local ejemplo2.local

En caso de no necesitar algunos co­n­te­ni­dos para una única página o para todo un sitio web, puedes in­tro­du­cir el valor 'none' en la cabecera de las di­re­c­ti­vas co­rre­s­po­n­die­n­tes. Así se indica que no se puede cargar ninguna fuente. Asimismo, también es posible utilizar el valor 'self' para indicar que el navegador solo debe recargar co­n­te­ni­dos de la misma fuente. Ambos valores deben ir siempre entre comillas simples, pues de lo contrario none y self se in­te­r­pre­ta­rán como dominios.

Para definir una política de seguridad de contenido hay diversas po­si­bi­li­da­des de cabecera:

  • Content Security Policy
  • X-Webkit-CSP
  • X-Content Security Policy

No todos los na­ve­ga­do­res son co­m­pa­ti­bles con cada de­no­mi­na­ción. El W3C (el gremio que define los es­tá­n­da­res en la Web) re­co­mie­n­da la Content Security Policy, por lo que todos los na­ve­ga­do­res modernos se han adaptado a este estándar de seguridad y las otras versiones están obsoletas. Para ase­gu­rar­te de que llegas con tu CSP al mayor número posible de usuarios de Internet (incluso a los que tienen versiones de navegador an­ti­cua­das), es aco­n­se­ja­ble integrar todos los campos de la cabecera. Si un navegador web no puede hacer nada con la cabecera de la Content Security Policy, la ignorará y mostrará la página web sin problemas, pero sin mostrarle la pro­te­c­ción adicional a los usuarios en cuestión. 

No­r­ma­l­me­n­te, las cabeceras HTTP se definen para todas las páginas del dominio. En el caso de los su­b­di­re­c­to­rios puede uti­li­zar­se el archivo .htaccess. Los es­tá­n­da­res de seguridad de CSP ayudan a es­ta­ble­cer reglas es­pe­cia­les para cada una de las su­b­pá­gi­nas. Si, por ejemplo, quieres im­ple­me­n­tar un botón para redes sociales en una página, pero no para la siguiente, solo es re­co­me­n­da­ble permitir el acceso a la fuente externa en la primera página.

Las fuentes pueden in­tro­du­ci­r­se como di­re­c­cio­nes, ya sea en su forma propia o como wildcards (comodines). Con respecto a ello, se permiten las si­guie­n­tes entradas:

  • script-src "https://example.com:443" – Solo se permiten scripts de este dominio por HTTPS.
  • script-src 'none' – No se pueden cargar scripts.
  • script-src 'self' – Solo pueden cargarse scripts que tengan el mismo origen que la página actual, pero no el de los su­b­do­mi­nios.
  • script-src https: – Se pueden cargar scripts de cualquier dominio siempre que empiecen por HTTPS.
  • script-src example.com – Se pueden cargar scripts de este dominio.
  • script-src *.example.com – Se permiten scripts de este y de todos los dominios.
  • img-src data: – Pueden cargarse imágenes por medio de enlaces de datos.  

Fu­n­da­me­n­ta­l­me­n­te, una Content Security Policy establece que solo pueden cargarse scripts a partir de archivos y no de forma directa desde el código de la página web. Para evitarlo, puedes recurrir al comando script-src 'unsafe-inline', pero siendo co­n­s­cie­n­te de que con ello puedes estar creando una brecha de seguridad. Asimismo, el estándar de seguridad también prohíbe la función eval (), comando con el que es posible tra­n­s­fo­r­mar texto en código Ja­va­S­cri­pt, algo que también plantea un riesgo para la seguridad. Si todavía se necesita esta función, puede volverse a activar con script-src 'unsafe-eval'.

Consejo

Dando un rodeo se puede asegurar unsafe-inline. Por medio de valores hash o de una fuente nonce pueden cerrarse las brechas de seguridad en gran medida.

Si ya no se permite que los scripts aparezcan di­re­c­ta­me­n­te en el código, se debe crear un archivo propio para cada uno de ellos. La función del script se ex­te­r­na­li­za en un archivo .js y el código de la página web solo hace re­fe­re­n­cia a este: 

<script src='ejemplo.js'></script>

Lo que hace fi­na­l­me­n­te el script está recogido en el archivo ejemplo.js. Asimismo, los elementos de estilo deben ex­te­r­na­li­zar­se en hojas de estilo separadas. Si como webmaster quieres adoptar una política de seguridad en Internet, no solo basta con insertar la cabecera, sino que también es necesario revisar y adaptar el código fuente.

Nota

¿Quieres conocer el nivel de seguridad de tu página? Para ello Mozilla te pro­po­r­cio­na un análisis muy útil: el proyecto Ob­se­r­va­to­ry by Mozilla asigna una nota al final del análisis y te informa de los aspectos que necesitan una mayor seguridad.

Un ejemplo de Content Security Policy

Con este ejemplo te mostramos cómo crear una cabecera para la política de seguridad de contenido y te ex­pli­ca­mos qué se puede conseguir con ella:

Content-Security-Policy: "default-src 'none'; script-src 'self' *.example.com; style-src 'self'; img-src 'self' data:; font-src 'self' https://fonts.google.com/; report-uri 'https://example.org/report.html' "

X-Content-Security-Policy: "default-src 'none'; script-src 'self' *.example.com; style-src 'self'; img-src 'self' data:; font-src 'self' https://fonts.google.com/; report-uri 'https://example.org/report.html' "

X-WebKit-CSP: "default-src 'none'; script-src 'self' *.example.com; style-src 'self'; img-src 'self' data:; font-src 'self' https://fonts.google.com/; report-uri 'https://example.org' "

En el ejemplo se observa que se ha añadido cada variante de CSP a la cabecera para poder abarcar al mayor número de na­ve­ga­do­res posible. Dentro de los re­s­pe­c­ti­vos nombres de cabecera, el contenido es idéntico: las fuentes se van nombrando de manera sucesiva, las di­re­c­ti­vas se separan con un punto y coma y la sintaxis es siempre la misma. En realidad, solo varía el nombre del campo, por lo que el contenido puede du­pli­car­se.

En primer lugar se establece que, a no ser que se haya definido de otra manera en una directiva, no se deben cargar datos de ninguna fuente (default-src). Con ello se cierra una brecha de seguridad. Siempre es co­n­ve­nie­n­te definir primero default-src para así evitar que una directiva olvidada provoque una brecha en tu Content Security Policy.  

El paso siguiente es definir la fuente desde la que se tienen que cargar los scripts (script-src). En el ejemplo se ha es­ta­ble­ci­do que el navegador solo cargue scripts de la misma fuente y de example.com, incluidos todos los su­b­do­mi­nios (la wildcard se adjudica mediante *). Además, también se indica que los clientes solo tienen permiso para cargar hojas de estilo desde la propia fuente (style-src) y, asimismo, también se permiten imágenes, pero solo desde la propia fuente y como URL de datos (img-src). Según nuestra cabecera de Content Security Policy, solo pueden cargarse tipos de letra del propio origen así como pro­ce­de­n­tes de la oferta de Google. Por último, en el ejemplo se ha indicado un lugar al que se deben enviar no­ti­fi­ca­cio­nes en caso de que alguien intente incumplir el estándar de seguridad (report-uri).

Sin embargo, la cabecera no incluye todas las di­re­c­ti­vas, lo que no supone un problema, pues en el ejemplo adoptado no se necesitan otras whi­te­li­sts y todas las fuentes se eliminan mediante default-src.

Consejo

En Internet existen numerosos ge­ne­ra­do­res de Content Security Policy. Con opciones como CSP Is Awesome o Report URI [Página de Report URI] (https://report-uri.io/home/generate) puedes crear cabeceras CSP de forma fácil y eficaz.

Ir al menú principal