Los headers que debemos evitar
Los encabezados o headers HTTP son una forma importante de controlar de qué modo procesan tu contenido web las memorias caché y los navegadores. Sin embargo, muchos se emplean de forma incorrecta o sin sentido, lo cual incrementa la carga de tu página en momentos críticos, y quizás no funcionen del modo que tenías previsto. En esta primera parte de una serie de entradas de blog sobre buenas prácticas en los headers, examinaremos los que son innecesarios.
La mayoría de los desarrolladores recurre a una serie de HTTP headers para sacar adelante sus contenidos. Los más conocidos incluyen Content-Type
y Content-Length
, que son prácticamente universales. No obstante, headers como Content-Security-Policy
y Strict-Transport-Security
han empezado a mejorar la seguridad más recientemente, y los headers Link rel=preload
, a mejorar el rendimiento. Son pocos los sitios que utilizan estos últimos, a pesar de la amplia compatibilidad que presentan los navegadores.
De forma paralela, hay un montón de headers que gozan de una tremenda popularidad pero que no son nuevos ni realmente son tan útiles. Podemos probar estas afirmaciones a través de HTTP Archive, proyecto dirigido por Google y promocionado por Fastly que carga 500.000 sitios web al mes por medio de WebPageTest y publica los resultados en BigQuery.
A partir de los datos de HTTP Archive, exponemos los 30 encabezados de respuesta más populares (en función del número de dominios del archivo que estén prestando servicios a cada header) y el grado de utilidad aproximada de todos y cada uno:
Nombre del encabezado | Peticiones | Dominios | Estado |
---|---|---|---|
date | 48779277 | 535621 | Protocolo obligatorio |
content-type | 47185627 | 533636 | Navegador obligatorio habitual |
server | 43057807 | 519663 | No necesario |
content-length | 42388435 | 519118 | Útil |
last-modified | 34424562 | 480294 | Útil |
cache-control | 36490878 | 412943 | Útil |
etag | 23620444 | 412370 | Útil |
content-encoding | 16194121 | 409159 | Obligatorio para comprimir contenido |
expires | 29869228 | 360311 | No necesario |
x-powered-by | 4883204 | 211409 | No necesario |
pragma | 7641647 | 188784 | No necesario |
x-frame-options | 3670032 | 105846 | No necesario |
access-control-allow-origin | 11335681 | 103596 | Útil |
x-content-type-options | 11071560 | 94590 | Útil |
link | 1212329 | 87475 | Útil |
age | 7401415 | 59242 | Útil |
x-cache | 5275343 | 56889 | No necesario |
x-xss-protection | 9773906 | 51810 | Útil |
strict-transport-security | 4259121 | 51283 | Útil |
a través de | 4020117 | 47102 | No necesario |
p3p | 8282840 | 44308 | No necesario |
expect-ct | 2685280 | 40465 | Útil |
content-language | 334081 | 37927 | Debatible |
x-aspnet-version | 676128 | 33473 | No necesario |
access-control-allow-credentials | 2804382 | 30346 | Útil |
x-robots-tag | 179177 | 24911 | No pertinente para navegadores |
x-ua-compatible | 489056 | 24811 | No necesario |
access-control-allow-methods | 1626129 | 20791 | Útil |
access-control-allow-headers | 1205735 | 19120 | Útil |
Echemos un vistazo a los headers innecesarios y analicemos por qué no los necesitamos y qué podemos hacer al respecto.
Vanidad (server, x-powered-by, via)
Podrás estar orgulloso/a del software de servidor que hayas elegido, pero a la mayoría de las personas esto no les interesa en absoluto. En el peor de los casos, estos encabezados quizás divulguen datos sensibles que podrían dejar a tu sitio expuesto a ciberataques.
Server: apache
X-Powered-By: PHP/5.1.1
Via: 1.1 varnish, 1.1 squid
La norma RFC 7231 permite que los servidores incluyan un header Server
en la respuesta, con lo que se identifica el software utilizado para proporcionar el contenido. Esto suele adoptar en la mayoría de los casos la forma de una cadena del tipo "apache" o "nginx". Aunque está permitido, no es obligatorio y ofrece muy poco valor a desarrolladores o usuarios finales. No obstante, se trata del tercer HTTP response header en popularidad a día de hoy en Internet.
X-Powered-By
es el header más popular de nuestra lista que no viene definido en norma alguna y cumple un fin parecido, aunque suele aludir a la plataforma de aplicaciones que subyace al servidor web. Los valores habituales incluyen "ASP.net", "PHP" y "Express". Insisto: esta información no aporta ventaja tangible alguna y ocupa espacio.
Más debatible quizás sea el caso de via
; según la norma RFC 7230, todo proxy a través del cual pase este header deberá agregarlo a la solicitud con fines de identificación. Posiblemente se trate del nombre de host del proxy, pero es más probable que sea un identificador genérico como "vegur", "varnish" o "squid". La supresión de este encabezado (o su no definición) respecto de una solicitud puede provocar que el proxy reenvíe bucles. Sin embargo, es interesante comprobar que este header también se copia en la respuesta que se devuelve al navegador y que, como tal, cumple fines meramente informativos que ningún navegador aprovecha; por lo tanto, es razonablemente seguro deshacerse del encabezado si así lo deseas.
Normas censuradas (P3P, Expires, X-Frame-Options, X-UA-Compatible)
Otra categoría de headers es la de aquellos que afectan al navegador pero que no son (o han dejado de ser) la mejor forma de lograr tal efecto.
P3P: cp="this is not a p3p policy"
Expires: Thu, 01 Dec 1994 16:00:00 GMT
X-Frame-Options: SAMEORIGIN
X-UA-Compatible: IE=edge
P3P
es un espécimen curioso. No tenía ni idea de lo que era y, lo que resulta más curioso aún, uno de sus valores más habituales es "this is not a p3p policy" (esta no es una política P3P). O sea, ¿lo es o no lo es?
En este caso, la historia se remonta a un intento de normalizar una política de privacidad de lectura mecánica. Había divergencias sobre cómo hacer aflorar los datos en los navegadores y un solo navegador llegó a implementar el encabezado: Internet Explorer. Y, sin embargo, ni siquiera con IE P3P
activaba efectos visuales para el usuario; solo tiene que estar presente para permitir el acceso a cookies de terceros en iframes. Algunos sitios incluso establecen una política P3P no conforme, como la anterior, a pesar de que hacerlo supone adentrarse en arenas movedizas desde el punto de vista jurídico.
Ni que decir tiene que la lectura de cookies de terceros es en general una mala idea, así que, si no es una práctica que sigas, ¡no tendrás por qué definir un header P3P
!
Expires
es increíblemente popular, sobre todo teniendo en cuenta que Cache-Control
ha estado por delante de Expires
en preferencia durante 20 años. En los casos en que el header Cache-Control
incluya una directiva del tipo max-age
, todo header Expires
que figure en la misma respuesta será ignorado. Sin embargo, existe un número ingente de sitios que definen ambos headers. De hecho, el valor más habitual de Expires
es Thu, 01 Dec 1994 16:00:00
GMT (jueves 1 de diciembre de 1994 a las 16.00 GMT); la razón: nadie quiere que su contenido se almacene en caché, de modo que copiar y pegar la fecha de ejemplo recogida en las especificaciones es sin duda una forma de conseguir este objetivo.
Pero no hay razón alguna para hacerlo. Si tienes un encabezado Expires
definido con una fecha del pasado, sustitúyelo con esto:
Cache-Control: no-store, private
(no-store
es una directiva muy rigurosa por la que se impide la escritura de contenido en el almacenamiento persistente; así que, en función de tu caso, quizás prefieras en realidad no-cache
para lograr un mejor rendimiento, por ejemplo, al utilizar los botones atrás/siguiente en la navegación o al volver a utilizar pestañas hibernadas).
Algunas de las herramientas que auditan tu sitio tienden a pedirte que incluyas un header X-Frame-Options
con un valor del tipo "SAMEORIGIN". Se indica así a los navegadores que rechazas ser integrado/a mediante marcos por otro sitio y, en líneas generales, es una buena estrategia de defensa frente al clickjacking. Sin embargo, se puede conseguir el mismo efecto, aunque con una compatibilidad más sistemática y una definición de comportamiento más sólida, haciendo lo siguiente:
Content-Security-Policy: frame-ancestors 'self'
Se logra así la ventaja complementaria de formar parte de un header CSP, que en cualquier caso deberías tener por otros motivos (veremos detalles al respecto más adelante). Por tanto, probablemente puedas prescindir de X-Frame-Options
en la actualidad.
Por último, en la época de IE9, Microsoft lanzó la función "Vista de compatibilidad", que permitía presentar un página que utilizara el motor de IE8 o IE7 aun navegando con IE9 si el navegador consideraba que la página podría necesitar la versión anterior para una presentación adecuada. Esa heurística no siempre daba en el clavo, y los desarrolladores fueron capaces de reemplazarla mediante el header o la meta etiqueta X-UA-Compatible
. De hecho, esta práctica pasó a emplearse habitualmente en marcos de trabajo como Bootstrap. En la actualidad, la función de este header apenas tiene utilidad: muy pocos usuarios utilizan navegadores que lo entenderían y, si mantienes tu sitio de forma activa, es muy improbable que utilices tecnologías que fueran a activar la vista de compatibilidad.
Datos de depuración (X-ASPNet-Version, X-Cache)
Resulta algo sorprendente que algunos de los headers cuyo uso se ha popularizado más no vengan recogidos en norma alguna. Esto quiere decir, fundamentalmente, que por alguna razón miles de sitios web parecen haber acordado de forma espontánea utilizar un header particular de un modo concreto.
X-Cache: HIT
X-Request-ID: 45a336c7-1bd5-4a06-9647-c5aab6d5facf
X-ASPNet-Version: 3.2.32
X-AMZN-RequestID: 0d6e39e2-4ecb-11e8-9c2d-fa7ae01bbebc
La realidad es que los desarrolladores de sitios web no acuñan estos headers "desconocidos" de forma aislada e independiente. Suelen tratarse de artefactos que guardan relación con el uso de marcos de trabajo de servidores concretos, software o servicios de distribuidores específicos (en este ejemplo, set, el último header, es un header AWS habitual).
Fastly y otras CDN añaden concretamente X-Cache
junto con otros headers relacionados con Fastly, como X-Cache-Hits
y X-Served-By
. Cuando se activa la depuración, añadimos más headers si cabe, como Fastly-Debug-Path
y Fastly-Debug-TTL
.
Ningún navegador reconoce estos headers y su eliminación no afecta en absoluto al modo de presentación de tus páginas. Sin embargo, dado que estos headers probablemente te proporcionen como desarrollador información útil, quizás te interese conservar una forma de activarlos.
Confusión (Pragma)
Aunque nunca pensé que escribiría una entrada de blog sobre el header Pragma
en el año 2018, este sigue ocupando el puesto 11.º en popularidad según nuestros datos de HTTP Archive. Pragma no solo fue censurado hace mucho en 1997, sino que en ningún caso pretendía ser un encabezado de respuesta: tal y como está especificado, únicamente adquiere significado como parte de una solicitud.
Pragma: no-cache
No obstante, su uso a modo de encabezado de respuesta está tan extendido que algunos navegadores también lo reconocen en este contexto. A día de hoy, las probabilidades de que tu respuesta transite por una caché que comprenda Pragma
dentro del contexto de una respuesta y que no comprenda Cache-Control
son cada vez más escasas. Si quieres asegurarte de que un contenido no se almacene en caché, lo único que necesitas es Cache-Control: no-store, private
.
Ajeno a navegadores (X-Robots-Tag)
De entre nuestros principales 30 headers, solo uno es ajeno a los navegadores. X-Robots-Tag
está diseñado para su consumo por parte de rastreadores como Google o de bots de Bing. Puesto que carece de significado para los navegadores, podrías optar por configurarlo únicamente cuando el agente de usuario solicitante sea un rastreador. Del mismo modo, podrías tomar la determinación de que este header dificulta la realización de pruebas o de que quizás infringe las condiciones de servicio del motor de búsquedas.
Errores
En último lugar, merece la pena concluir haciendo mención honorífica de los simples errores. El header Host
tiene sentido en cualquier solicitud , pero su inclusión en una respuesta quizás nos esté indicando que tu servidor está mal configurado por algún motivo (me encantaría saber exactamente cuál). No obstante, 68 dominios de HTTP Archive devuelven en sus respuestas el encabezado Host
.
Eliminación de headers en el borde
Por suerte, si tu sitio subyace a Fastly, la eliminación de headers es muy sencilla a través de VCL. Es lógico que quieras conservar los datos de depuración que sean verdaderamente útiles y ponerlos a disposición de tu equipo de desarrollo, pero ocultos a los usuarios públicos; esto se consigue fácilmente detectando una cookie o un HTTP header entrante:
En la siguiente entrada de blog de la serie, hablaré de las buenas prácticas respecto a los headers que deberías ir implantando y de qué modo activarlas en el borde.