// Engineering Log
HTTP, HTTPS y TLS: Parte 2 — Cabeceras HTTP: cuáles hay y para qué sirven
Publicado el 28.09.2026
// Ruta rapida
Este articulo pertenece al tema Seguridad y proteccion.
Los encabezados son metadatos de un mensaje HTTP: líneas del tipo Nombre: valor entre la línea de inicio y el cuerpo. A través de ellos el servidor entiende qué sitio se solicita, en qué formato y en qué idioma entregar la respuesta, quién está delante de él y si el cliente tiene una copia actual. El navegador, según los encabezados de respuesta, decide cómo mostrar el contenido, si se puede cachear y qué restricciones de seguridad aplican en la página.
A continuación se analizan los encabezados que aparecen constantemente en el trabajo, por grupos. Puedes verlos en cualquier sitio con el comando:
curl -sI https://example.ru/ # solo cabeceras de la respuesta (método HEAD)
curl -sv -o /dev/null https://example.ru/ 2>&1 | grep -E '^[<>]' # solicitud y respuestaCómo están estructurados los encabezados
- Los nombres no dependen de mayúsculas/minúsculas. En HTTP/2 y HTTP/3 siempre son minúsculas, y en los registros verás
content-typeen lugar deContent-Type. - Un encabezado puede aparecer varias veces; sus valores se combinan separados por comas. La excepción es
Set-Cookie: cada cookie va en una línea separada. - El prefijo
X-alguna vez indicó encabezados no estándar. RFC 6648 (2012) recomienda dejar de usarlo, pero nombres antiguos comoX-Forwarded-Forsiguen en uso. - El tamaño de los encabezados lo limita el servidor. En Nginx el buffer para la línea de petición y los encabezados se define con
large_client_header_buffers(por defecto 4 buffers de 8 KB); si las cookies crecieron demasiado, el servidor responderá400 Request Header Or Cookie Too Large.
Encabezados de la solicitud
Host — nombre del sitio y puerto si no es estándar. En una misma dirección IP pueden alojarse cientos de sitios, y el servidor web selecciona el correcto precisamente por Host (en Nginx — por server_name). Este es el único encabezado obligatorio en HTTP/1.1. En HTTP/2 y HTTP/3 su papel lo desempeña el pseudo-encabezado :authority.
User-Agent — quién hace la solicitud: el navegador y su versión, curl/8.7.1, python-requests/2.32. Los servidores lo usan para estadísticas y a veces para bloquear bots. El valor lo rellena el propio cliente, por lo que cualquiera puede falsificarlo; indicios más fiables del cliente son las huellas TLS, sobre ellas — «Qué son JA3 y JA4».
Accept, Accept-Language, Accept-Encoding — negociación de contenido. El cliente enumera lo que puede aceptar, con pesos q:
Accept: text/html,application/xhtml+xml,*/*;q=0.8
Accept-Language: ru-RU,ru;q=0.9,en;q=0.8
Accept-Encoding: gzip, deflate, br, zstdEl servidor elige una variante y comunica la elección en Content-Type, Content-Language y Content-Encoding. Si la respuesta depende de uno de estos encabezados, el servidor debe añadir Vary: Accept-Encoding (u otro nombre), de lo contrario los proxy y CDN pueden dar una versión comprimida a un cliente que no la entiende.
Authorization — credenciales. Basic — usuario y contraseña en Base64 (es una codificación, no un cifrado: sin HTTPS la contraseña se lee tal cual). Bearer — token, por ejemplo JWT o clave API.
Cookie — cookies que el navegador guardó para este sitio: Cookie: session=abc123; lang=ru.
Referer — dirección de la página desde la que vino el usuario (la palabra está mal escrita ya en la primera especificación y así quedó). Cuánta información enviar se determina por el encabezado de respuesta Referrer-Policy; por defecto los navegadores envían a otros sitios solo el dominio.
Origin — esquema, host y puerto de la página desde la que se envió la solicitud. El navegador lo añade a solicitudes a otro sitio y a POST; sobre él se basan CORS y la comprobación contra CSRF.
If-None-Match, If-Modified-Since — solicitudes condicionales. El navegador informa qué versión ya tiene y el servidor responde con un corto 304 Not Modified sin cuerpo si no ha cambiado nada.
Range — petición de una parte del archivo: Range: bytes=1000000-. Sirve para reanudar descargas y para seek en vídeo.
Content-Type, Content-Length — tipo y longitud del cuerpo de la solicitud. Para formularios — application/x-www-form-urlencoded o multipart/form-data, para APIs — normalmente application/json. Error frecuente: JSON enviado sin Content-Type: application/json, y la aplicación no ve los datos.
Encabezados de respuesta sobre el contenido
Content-Type — qué hay en el cuerpo y en qué codificación: text/html; charset=utf-8, application/json, image/webp. El navegador decide cómo mostrar la respuesta basándose en él. Para evitar que el navegador intente adivinar el tipo (lo que llevaba a ejecutar archivos subidos por usuarios como scripts) se añade X-Content-Type-Options: nosniff.
Content-Encoding — cómo está comprimido el cuerpo: gzip, br (Brotli), zstd.
Content-Disposition — mostrar el archivo en el navegador (inline) o sugerir descargarlo (attachment; filename="report.pdf").
Location — dirección para redirección en respuestas 3xx y dirección del recurso creado en la respuesta 201 Created.
Server — programa del servidor web. Es mejor no revelar la versión: en Nginx — server_tokens off;.
Caché
Hay caché en el navegador, en CDN y en proxies. Las reglas para ellos las define el servidor.
Cache-Control — el encabezado principal de caché:
max-age=3600— la respuesta es fresca durante una hora; en ese tiempo el navegador la toma de la caché sin consultar al servidor;s-maxage=600— lo mismo para cachés compartidas (CDN, proxies), tiene prioridad sobremax-age;no-cache— se puede almacenar, pero antes de usar se debe verificar con el servidor (víaIf-None-Match);no-store— no almacenar en absoluto; para páginas con datos personales;private— solo el navegador, las CDN no deben almacenarla; para páginas que dependen del usuario;public— se puede almacenar en cachés compartidas;immutable— el recurso nunca cambiará; se usa en archivos con hash en el nombre (app.3f9a1c.js) junto con unmax-agegrande.
El nombre no-cache induce a confusión: no prohíbe el almacenamiento en caché. Para prohibirlo hay no-store.
ETag — identificador de la versión del recurso (por ejemplo, hash del contenido). El navegador lo devuelve en If-None-Match. Last-Modified — fecha de modificación, se devuelve y se usa en If-Modified-Since.
Age — cuántos segundos lleva la respuesta en la caché del CDN o proxy. Si hay Age, la respuesta no vino de tu servidor. Los CDN con frecuencia añaden encabezados propios: CF-Cache-Status: HIT en Cloudflare, X-Cache: HIT en muchos otros.
Cookies
El servidor establece cookies con el encabezado Set-Cookie, una por cada cookie:
Set-Cookie: session=abc123; Path=/; Secure; HttpOnly; SameSite=Lax; Max-Age=86400Secure— enviar solo por HTTPS;HttpOnly— no accesible desde JavaScript, un script inyectado no la robará;SameSite=Lax— no enviar en solicitudes desde sitios externos, salvo la navegación normal por enlace;Strict— nunca desde sitios externos;None— siempre (solo junto conSecure). Los navegadores modernos, si no se especifica, tratan las cookies comoLax;Max-AgeoExpires— tiempo de vida; sin ellos la cookie se borra al cerrar el navegador;Domain— si se especifica, la cookie se envía también a subdominios. Sin él — solo al host que la estableció.
Para una cookie de sesión, el mínimo sensato es Secure; HttpOnly; SameSite=Lax.
CORS
El navegador no permite que JavaScript de la página https://app.example.ru lea respuestas de https://api.example.ru si el servidor API no lo ha permitido explícitamente. Esta regla es la política de mismo origen (same-origin policy), y CORS es el mecanismo de permisos:
Access-Control-Allow-Origin: https://app.example.ru
Access-Control-Allow-Credentials: truePara solicitudes “no simples” — con métodos PUT y DELETE, con Content-Type: application/json, con el encabezado Authorization — el navegador primero envía una petición preliminar OPTIONS con los encabezados Access-Control-Request-Method y Access-Control-Request-Headers. El servidor responde qué está permitido (Access-Control-Allow-Methods, Access-Control-Allow-Headers, Access-Control-Max-Age), y solo entonces se envía la solicitud real.
Detalles importantes:
- CORS protege al usuario del navegador, no al servidor. curl y cualquier script fuera del navegador no aplican CORS;
Access-Control-Allow-Origin: *no funciona junto con cookies yAuthorization— para peticiones con credenciales se necesita un origen concreto;- si el error CORS se ve en la consola, primero mira la respuesta al
OPTIONS: a menudo la bloquea la autenticación o el servidor responde con 404/405.
Encabezados de seguridad
Strict-Transport-Security(HSTS) — “accede a este sitio solo por HTTPS”:max-age=31536000; includeSubDomains. Más detalles — «Transición a HTTPS: redirecciones, HSTS, HTTPS-First».Content-Security-Policy— de dónde la página puede cargar scripts, estilos, imágenes, a dónde enviar formularios. La principal protección contra XSS. Ejemplo:default-src 'self'; img-src 'self' data:; frame-ancestors 'none'. Es cómodo empezar conContent-Security-Policy-Report-Only: el navegador informa de las violaciones en la consola, pero no bloquea nada.X-Frame-Options: DENYo la directiva CSPframe-ancestors— prohíben incrustar el sitio en un iframe en páginas ajenas (protección contra clickjacking).X-Content-Type-Options: nosniff— no adivinar el tipo de contenido.Referrer-Policy: strict-origin-when-cross-origin— no enviar a sitios externos la URL completa de la página.Permissions-Policy— qué capacidades del navegador están disponibles para la página:camera=(), microphone=(), geolocation=().
El encabezado X-XSS-Protection está obsoleto: los navegadores modernos lo ignoran; en su lugar se usa CSP.
En Nginx los encabezados de respuesta se añaden con la directiva add_header, y tiene una trampa: si en un bloque location hay al menos un add_header, los encabezados del nivel server no se aplican en ese bloque. El parámetro always es necesario para que el encabezado se envíe también en respuestas de error:
server {
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
}Encabezados de proxy
Cuando delante de la aplicación hay Nginx, HAProxy o un CDN, la aplicación ve la conexión desde el proxy, no desde el cliente. El proxy transmite los datos originales en encabezados:
X-Forwarded-For: 192.0.2.7, 192.0.2.2— cadena de direcciones: el cliente y todos los proxies en la ruta;X-Forwarded-Proto: https— por qué protocolo vino el cliente; sin él, la aplicación detrás de un proxy que recibe HTTPS pensará que funciona por HTTP y construirá enlaces incorrectos o caerá en un redireccionamiento infinito a HTTPS;X-Forwarded-Host—Hostoriginal;X-Real-IP— dirección del cliente en un solo valor (convención de Nginx);Forwarded: for=192.0.2.7;proto=https— sustitución estándar para todos los anteriores (RFC 7239), menos soportada.
Se puede confiar en estos encabezados solo si los puso tu proxy. El cliente puede enviar X-Forwarded-For por su cuenta, y una aplicación que tome la primera dirección de la lista recibirá una falsificación. Regla: toma la dirección añadida por el último proxy de confianza, y en Nginx especifica explícitamente las redes de confianza:
set_real_ip_from 10.0.0.0/8;
real_ip_header X-Forwarded-For;
real_ip_recursive on;Encabezados de control de la conexión
Connection, Keep-Alive, Transfer-Encoding, Upgrade se refieren a un único tramo del recorrido — entre el cliente y el proxy más cercano — y no se transmiten más allá. En HTTP/2 y HTTP/3 están prohibidos. Por eso, para proxificar WebSocket a través de Nginx, hay que reenviar Upgrade y Connection explícitamente a la aplicación — ejemplo en el artículo «Transición a HTTPS y el encabezado Upgrade».
Errores comunes
- No se definió
Cache-Control— los navegadores y CDN hacen caché por heurística (a menudo 10 % de la antigüedad deLast-Modified), y los usuarios ven estilos antiguos después del despliegue. no-cacheen lugar deno-storeen páginas con datos personales.- La respuesta depende de cookies o del idioma, pero no se puso
Varyniprivate— el CDN da a un usuario la página de otro. Access-Control-Allow-Originse toma delOriginde la solicitud sin verificarlo en una lista — es lo mismo que permitir a todos, pero con cookies.- La aplicación confía en
X-Forwarded-Forde cualquier cliente — se elude la restricción por IP y los registros se falsifican.
// Tarea parecida
Si estas resolviendo algo parecido
Este articulo pertenece a uno de los temas principales de trabajo. Puedes seguir leyendo sobre el tema, ir a la pagina principal para entender a que me dedico o abrir directamente los servicios.
Tema del articulo
Seguridad y proteccion
SSL, hardening, accesos, proteccion de servicios y configuraciones seguras.
Tareas frecuentes de esta tema
- Configurar SSL, certificados y conexiones seguras
- Restringir accesos y cerrar puntos de entrada innecesarios
- Reforzar la configuracion del servidor y los servicios
// Siguiente paso
Si necesitas ayuda con este tema y no solo otro articulo, es mejor ir directo a la pagina del servicio. La pagina principal y la seleccion de materiales quedan como rutas secundarias.
Abrir servicios// Contact
¿Necesitas ayuda?
Escríbeme y te ayudaré a resolver el problema
Respondo en un día laborable (03:00-13:00 GMT)
Или оставьте заявку здесь:
// Related