Resumen

  • El primer borrador público de Content Security Policy, fechado el 29 de noviembre de 2011, propuso que un sitio declarara de dónde podían cargarse sus recursos y que el navegador hiciera cumplir esa decisión.
  • La Recomendación de nivel 2, del 15 de diciembre de 2016, describió políticas aplicadas y de solo informe, además de nonces y huellas para reconocer scripts incrustados concretos. El sitio escribía la lista; el navegador atendía la puerta.

El sitio había organizado una fiesta sin apuntar a los invitados. Llegó un script del proveedor de siempre, otro de un complemento que nadie recordaba, una fila de imágenes, varias fuentes y unas conexiones que venían de bastante lejos. Entre todos ellos podía colarse un fragmento de código con malas intenciones. Hacía falta un portero, pero el dueño de la casa debía entregarle algo más útil que un gesto vago hacia la multitud.

El primer borrador público del W3C sobre Content Security Policy, del 29 de noviembre de 2011, planteó esa división del trabajo. Su resumen describía una política declarativa para limitar los lugares desde los que una aplicación web cargaba recursos y mitigar inyecciones de contenido, entre ellas los scripts entre sitios. El sitio decía qué procedencias aceptaba. El navegador comprobaba las peticiones concretas antes de dejar pasar cada recurso.

El borrador no proponía una pegatina general que dijera «de confianza». Separaba default-src de reglas para scripts, imágenes, estilos, fuentes, marcos, medios y conexiones. Una página podía admitir fotografías de varios lugares y reservar a los scripts un círculo más pequeño. La diferencia importa: un retrato en la pared y alguien con acceso a la mesa de luces no hacen el mismo trabajo. La lista de invitados debía distinguir sus oficios.

También obligaba al editor a mirarse al espejo. El sitio sabía qué proveedores pretendía usar; el navegador veía la solicitud que realmente salía. La política unía ambas perspectivas. Escribir script-src llevaba segundos. Averiguar si una página antigua dependía todavía de un widget olvidado podía consumir una tarde. Una lista demasiado corta podía detener un script intruso y, de paso, romper el pago de una compra. El problema no era la mala memoria del portero. Era el archivo de invitados del anfitrión.

La Recomendación Content Security Policy Level 2 del W3C, publicada el 15 de diciembre de 2016, dio al portero un turno de observación. Con la cabecera Content-Security-Policy-Report-Only, el navegador vigilaba las infracciones de una política propuesta y enviaba informes, pero dejaba cargar los recursos. El propio texto proponía probar así una regla, observar las coincidencias y pasar después a la cabecera que sí la aplicaba: Content-Security-Policy. Primero se anotaban las caras; luego se cerraba la cuerda roja.

Ese ensayo servía para algo más que suavizar un estreno. Un informe podía señalar una fuente cargada desde una dirección inesperada, un servicio de análisis heredado o una petición lanzada por un componente que llevaba años sin dueño. La observación del navegador describía la petición. Al equipo le tocaba decidir si el recurso respondía a una función querida, si había que corregir la página o si aquel invitado debía dejar de aparecer. El modo de solo informe convertía el desorden del sitio en una lista que alguien podía examinar.

La ubicación de la política importaba. La Recomendación de 2016 prefería una cabecera HTTP recibida con la respuesta; también permitía incluir reglas en un elemento HTML meta colocado pronto. Una regla escrita en meta no alcanzaba a los recursos cargados antes de ella y no ofrecía el modo de solo informe. Pegar el cartel de admisión detrás de la pista de baile sirve poco para vigilar la entrada. La cabecera llegaba al navegador antes de que empezara el desfile de elementos de la página.

Los scripts incrustados planteaban la invitación más delicada. Una web podía necesitar algunos, pero permitir cualquier código escrito dentro del documento abría paso también al código inyectado. El nivel 2 describió nonces y huellas para identificar bloques concretos. El servidor podía generar un valor aleatorio para la respuesta y ponerlo tanto en la política como en los elementos elegidos; una huella podía reconocer el contenido exacto de un script. Era una invitación para una persona, no una orden de abrir la puerta a cualquiera que llevara una etiqueta de JavaScript.

Había varias puertas. img-src trataba las imágenes; connect-src, ciertas conexiones; base-uri, la dirección base de los enlaces relativos; form-action, los destinos de formularios; y frame-ancestors, las páginas que podían mostrar el sitio dentro de un marco. Un editor podía tomar decisiones distintas para cada actividad. El navegador veía el momento en que ocurrían y aplicaba la regla correspondiente. Ese reparto era más útil que una lista única de dominios supuestamente buenos.

El historial de publicación de CSP Level 2 del W3C sitúa la Recomendación de diciembre de 2016 después de sus borradores. Son fechas de documentos técnicos. El cambio histórico está en la rutina que dejaron: el editor formula una intención, el navegador comprueba las cargas y los informes muestran dónde la página real se aparta del plan. Internet ganó un portero; las webs tuvieron que aprender a reconocer a sus propios clientes habituales.

Quien abre una noticia o intenta pagar una entrada no lee antes la cabecera Content-Security-Policy. Ve la página funcionando o un componente roto porque alguien olvidó apuntarlo. La lista opera entre bambalinas. Puede mantener fuera al código que nunca tuvo invitación, pero solo si la casa sabe quién tenía que estar dentro. El navegador hace un buen trabajo con una lista honesta. Pedirle que adivine los nombres sería convertir al portero en adivino.