Infraestructura digital funcionando a pleno rendimiento. Racks de servidores con conexiones y luces azules en un centro de datos.
Un sitio web sin encabezados de seguridad HTTP puede parecer impecable: diseño limpio, formularios elegantes, velocidad aceptable, certificado SSL brillante como una medalla recién pulida. Pero debajo, en el diálogo silencioso entre navegador y servidor, quizá va desnudo por la plaza pública. Y lo curioso —la pequeña ironía técnica de nuestro tiempo— es que muchas de estas defensas se configuran con unas pocas líneas.
Los encabezados de seguridad HTTP, también llamados Security Headers, son instrucciones que el servidor envía al navegador para decirle cómo debe comportarse frente a ciertos riesgos: ataques XSS, clickjacking, filtración de datos por referencias, abuso de APIs del navegador, carga de contenido inseguro, exposición de cookies, políticas de aislamiento y otras criaturas discretas que rara vez salen en la portada, pero que trabajan en la sombra.
¿Son “obligatorios”? Depende de qué entendamos por obligatorio. No existe una única ley universal que diga: “todo servidor deberá llevar exactamente estos siete encabezados o será arrojado a las tinieblas”. Sería cómodo, sí. También ingenuo. En seguridad web, lo obligatorio se construye entre varios mundos: estándares técnicos, cumplimiento normativo, auditorías, requisitos de clientes, buenas prácticas de OWASP, recomendaciones de navegadores, políticas internas y, por supuesto, el sentido común, ese pariente pobre al que llamamos cuando el incidente ya está en producción.
Lo que sí existe es un conjunto mínimo profesional que cualquier sitio serio debería implementar. Un servidor moderno sin estos encabezados se parece a una casa con cerradura biométrica en la puerta principal y ventanas abiertas en el sótano. Muy tecnológico. Muy vulnerable.
En esta guía veremos:
- Qué encabezados de seguridad HTTP son imprescindibles en un servidor moderno.
- Cuáles son recomendables, cuáles dependen del caso y cuáles conviene evitar.
- Cómo configurarlos en Apache, Nginx, WordPress, Cloudflare y otros entornos.
- Errores frecuentes que rompen sitios o generan una falsa sensación de protección.
- Una lista práctica de verificación para producción. ✅
Primero: qué son realmente los Security Headers
Cada vez que visitas una página, tu navegador pide recursos al servidor: documentos HTML, hojas CSS, JavaScript, imágenes, fuentes, llamadas a APIs. La respuesta del servidor no trae solo contenido; trae también metadatos. Entre ellos están los encabezados HTTP.
Algunos encabezados son funcionales, como Content-Type o Cache-Control. Otros son defensivos: restringen, advierten, aíslan, limitan. Son como señales de tráfico en una ciudad digital. No impiden que existan malos conductores, pero reducen el caos y hacen que ciertas maniobras sean directamente imposibles.
Un ejemplo simple:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin
Content-Security-Policy: default-src 'self'; object-src 'none'; base-uri 'self'
Permissions-Policy: camera=(), microphone=(), geolocation=()
Estas líneas no decoran. Ordenan al navegador que use HTTPS, que no adivine tipos MIME, que limite la información enviada en el encabezado Referer, que solo cargue recursos desde orígenes permitidos y que bloquee funciones sensibles como cámara, micrófono o geolocalización salvo autorización explícita.
El contraste es casi literario: el servidor habla en frases breves; el navegador obedece con consecuencias enormes.
¿“Obligatorios” para quién? La respuesta honesta
La palabra obligatorio conviene tratarla con cuidado. En seguridad, exagerar es fácil; precisar cuesta más.
Un encabezado puede ser obligatorio por:
- Requisitos de auditoría o compliance: PCI DSS, ISO 27001, SOC 2, ENS, políticas corporativas o auditorías de seguridad pueden exigir ciertos controles.
- Buenas prácticas reconocidas: OWASP Secure Headers Project, Mozilla Observatory, recomendaciones de Google y documentación de navegadores modernos.
- Necesidad técnica: si tu sitio usa cookies de sesión, HTTPS, iframes, APIs, pagos, paneles privados o datos personales, ciertos encabezados dejan de ser “opcionales simpáticos”.
- Riesgo de negocio: no es lo mismo un blog personal que una tienda WooCommerce con datos de clientes, pagos, sesiones administrativas y píxeles de terceros haciendo su pequeño carnaval.
Idea clave: no todos los encabezados son obligatorios para todos los sitios, pero todo sitio profesional debería tener una política mínima de encabezados de seguridad. En 2026, no configurarlos ya no es descuido inocente; es negligencia con buena conexión a Internet.
La lista corta: encabezados imprescindibles en casi cualquier servidor 🔐
Si necesitas una respuesta directa, aquí está el núcleo duro. Estos son los encabezados que, en la mayoría de sitios web modernos, deberían estar presentes o evaluados seriamente antes de publicar en producción.
| Encabezado | Prioridad | Función principal | ¿Cuándo usarlo? |
|---|---|---|---|
Strict-Transport-Security |
Muy alta | Fuerza el uso de HTTPS y reduce ataques de downgrade. | Sitios con HTTPS estable en todo el dominio. |
Content-Security-Policy |
Muy alta | Controla desde dónde se cargan scripts, estilos, imágenes, frames y otros recursos. | Casi todos los sitios; requiere pruebas cuidadosas. |
X-Content-Type-Options |
Alta | Evita que el navegador “adivine” tipos de archivo. | Todos los sitios. |
Referrer-Policy |
Alta | Controla cuánta información se envía en el encabezado Referer. | Todos los sitios, especialmente con rutas sensibles. |
X-Frame-Options o frame-ancestors en CSP |
Alta | Previene clickjacking al limitar si tu sitio puede ser incrustado en iframes. | Paneles, tiendas, login, formularios, áreas privadas. |
Permissions-Policy |
Media-alta | Limita APIs del navegador como cámara, micrófono, geolocalización, sensores. | Todos los sitios, con ajustes según funcionalidades. |
Set-Cookie con Secure, HttpOnly, SameSite |
Crítica | Protege cookies de sesión y reduce robo o abuso cross-site. | Cualquier sitio con login, sesiones, carrito o panel. |
Cache-Control |
Alta en áreas sensibles | Evita que datos privados queden almacenados en cachés o navegadores compartidos. | Login, checkout, paneles, cuentas de usuario, APIs privadas. |
1. Strict-Transport-Security: HTTPS sin marcha atrás
Strict-Transport-Security, conocido como HSTS, le dice al navegador: “durante este tiempo, visita este dominio solo por HTTPS”. Es una barrera contra ataques de tipo SSL stripping, donde un atacante intenta degradar la conexión a HTTP para espiar o manipular tráfico.
Ejemplo recomendado para un sitio maduro:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
Significado:
max-age=31536000: el navegador recordará la política durante un año.includeSubDomains: aplica también a todos los subdominios.preload: permite solicitar inclusión en la lista HSTS preload usada por navegadores principales.
Atención: HSTS es poderoso, pero no perdona improvisaciones. Si activas includeSubDomains y tienes un subdominio antiguo sin HTTPS, lo romperás. Y si entras en la lista preload, salir no es inmediato. Es como tatuar una instrucción en la memoria colectiva de los navegadores: conviene estar sobrio antes de hacerlo.
Versión prudente para empezar:
Strict-Transport-Security: max-age=300
Después de validar que todo funciona por HTTPS, se puede subir gradualmente a seis meses o un año:
Strict-Transport-Security: max-age=15552000; includeSubDomains
Y, solo si todo el ecosistema está preparado:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
2. Content-Security-Policy: el muro inteligente contra XSS
Si HSTS es una orden firme, Content-Security-Policy —CSP— es un tratado diplomático con aduanas, fronteras y permisos de importación. Define qué recursos puede cargar una página y desde dónde: scripts, estilos, imágenes, fuentes, conexiones, iframes, objetos, formularios.
Una CSP bien diseñada puede reducir drásticamente el impacto de ataques Cross-Site Scripting —XSS—. No sustituye la validación de entradas, el escape de salidas ni el desarrollo seguro. Quien crea eso probablemente también piensa que un paraguas detiene un huracán. Pero como capa defensiva, CSP es una de las más valiosas.
Política base razonable para empezar:
Content-Security-Policy: default-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'self'; form-action 'self'; upgrade-insecure-requests
Directivas importantes:
default-src: valor por defecto para cargar recursos si no hay una directiva específica.script-src: controla JavaScript. Es la parte más delicada.style-src: controla CSS.img-src: controla imágenes.font-src: controla fuentes.connect-src: controla conexiones AJAX, Fetch, WebSocket, APIs.frame-src: define qué puede ser embebido dentro de tu sitio.frame-ancestors: define quién puede embeber tu sitio.object-src: bloquea plugins antiguos como Flash, Silverlight o Java applets. Sí, hay fantasmas que tardan en irse.base-uri: evita manipulación de etiquetas<base>.form-action: limita a dónde pueden enviarse formularios.upgrade-insecure-requests: intenta actualizar recursos HTTP a HTTPS.
CSP en modo informe antes de bloquear
Para evitar romper el sitio de golpe, puede usarse Content-Security-Policy-Report-Only. El navegador no bloquea, pero informa violaciones.
Content-Security-Policy-Report-Only: default-src 'self'; script-src 'self'; object-src 'none'; report-uri https://tudominio.com/csp-report
Es una etapa sensata para sitios complejos, especialmente WordPress con plugins de analítica, píxeles publicitarios, chatbots, constructores visuales y otros invitados que entran al salón con barro en los zapatos.
El problema de 'unsafe-inline'
Muchas implementaciones de CSP acaban así:
Content-Security-Policy: script-src 'self' 'unsafe-inline' 'unsafe-eval' *
Eso no es una política de seguridad; es una carta de amor al desorden. 'unsafe-inline' permite scripts inline, uno de los vectores clásicos de XSS. 'unsafe-eval' habilita evaluación dinámica de código. Y * abre demasiado la puerta.
Lo ideal es usar nonces o hashes para permitir solo scripts autorizados:
Content-Security-Policy: script-src 'self' 'nonce-r4nd0mSeguro'; object-src 'none'; base-uri 'self'
En aplicaciones modernas, los nonces se generan por respuesta y se aplican a los scripts legítimos. En WordPress puede ser más complicado, pero no imposible: algunos plugins de seguridad avanzados, configuraciones personalizadas o capas de proxy permiten aproximarse bastante.
3. X-Content-Type-Options: no dejes que el navegador improvise
El encabezado X-Content-Type-Options con valor nosniff impide que el navegador interprete archivos como un tipo distinto al declarado por el servidor.
X-Content-Type-Options: nosniff
¿Por qué importa? Porque algunos navegadores históricamente intentaban “adivinar” el contenido. Si un archivo subido por un usuario parecía JavaScript aunque el servidor lo sirviera como texto, podía ejecutarse. Una maravillosa cortesía del navegador, como si un portero dejara pasar a cualquiera porque “parecía vecino”.
Este encabezado es sencillo, ampliamente soportado y prácticamente obligatorio en cualquier configuración seria.
4. X-Frame-Options y frame-ancestors: defensa contra clickjacking
El clickjacking consiste en incrustar tu sitio dentro de un iframe invisible o manipulado para engañar al usuario y hacerle clic donde no quería. El usuario cree que pulsa un botón inocente; en realidad confirma una acción en otro sitio. La trampa es tan vieja como efectiva.
Encabezado clásico:
X-Frame-Options: SAMEORIGIN
Valores comunes:
DENY: nadie puede incrustar la página en un frame.SAMEORIGIN: solo páginas del mismo origen pueden hacerlo.
La alternativa moderna es usar frame-ancestors dentro de CSP:
Content-Security-Policy: frame-ancestors 'self' https://socio-autorizado.com
frame-ancestors es más flexible y debería preferirse en navegadores modernos. Aun así, muchas configuraciones mantienen también X-Frame-Options por compatibilidad.
Recomendación práctica: si tu sitio no necesita ser embebido por terceros, usa frame-ancestors 'self' o DENY. Si trabajas con pasarelas, plataformas educativas, CRM o integraciones que usan iframes, documenta exactamente qué dominios están permitidos.
5. Referrer-Policy: discreción en tiempos de rastreo permanente
Cuando un usuario hace clic desde tu sitio hacia otro, el navegador puede enviar el encabezado Referer —sí, mal escrito históricamente; la web también tiene sus fósiles ortográficos— indicando la URL de origen.
Esto puede revelar información sensible: rutas internas, parámetros, tokens mal diseñados, búsquedas, identificadores. La Referrer-Policy controla cuánto se comparte.
Valor recomendado para la mayoría de sitios:
Referrer-Policy: strict-origin-when-cross-origin
Este valor suele equilibrar privacidad y funcionalidad:
- Envía la URL completa al navegar dentro del mismo origen.
- Envía solo el origen —por ejemplo,
https://ejemplo.com— al ir a otro sitio HTTPS. - No envía referrer desde HTTPS hacia HTTP.
Opciones más restrictivas:
Referrer-Policy: no-referrer
O:
Referrer-Policy: same-origin
La elección depende de analítica, afiliación, integraciones y privacidad. Para sitios con datos sensibles, no-referrer puede ser conveniente. Para sitios comerciales que necesitan atribución básica sin exponer rutas completas, strict-origin-when-cross-origin suele ser una buena brújula.
6. Permissions-Policy: poner límites a las capacidades del navegador 🎛️
Antes conocida como Feature-Policy, Permissions-Policy permite controlar qué APIs del navegador pueden usarse: cámara, micrófono, geolocalización, acelerómetro, pantalla completa, pagos, USB, interés cohortado —cuando existía FLoC— y otras funciones.
Ejemplo conservador:
Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=(), usb=(), fullscreen=(self)
Esto indica:
- Nadie puede usar cámara.
- Nadie puede usar micrófono.
- Nadie puede solicitar geolocalización.
- Nadie puede usar pagos del navegador.
- Nadie puede usar USB.
- Solo el propio sitio puede usar pantalla completa.
Si tu aplicación necesita geolocalización, por ejemplo una tienda con buscador de sucursales, puedes permitirla en tu propio origen:
Permissions-Policy: geolocation=(self), camera=(), microphone=()
La belleza de este encabezado está en su sobriedad: desactiva lo que no necesitas. En seguridad, lo que no existe no se explota; lo que no se habilita no se abusa.
7. Cookies seguras: no basta con Set-Cookie
Aunque Set-Cookie no siempre aparece en las listas de “security headers” tradicionales, en la práctica es uno de los puntos más críticos. Las cookies sostienen sesiones, carritos, autenticación, preferencias y tokens. Son pequeñas, persistentes y peligrosamente confiadas si se configuran mal.
Una cookie de sesión debería incluir:
Set-Cookie: session_id=abc123; Secure; HttpOnly; SameSite=Lax; Path=/
Atributos esenciales:
Secure: la cookie solo viaja por HTTPS.HttpOnly: JavaScript no puede leerla mediantedocument.cookie, lo que reduce impacto de XSS.SameSite: limita el envío de cookies en solicitudes cross-site y ayuda contra CSRF.PathyDomain: delimitan alcance.Max-AgeoExpires: controlan duración.
SameSite: Lax, Strict o None
| Valor | Uso habitual | Advertencia |
|---|---|---|
SameSite=Strict |
Máxima protección cross-site. | Puede romper flujos legítimos al venir desde enlaces externos, SSO o pagos. |
SameSite=Lax |
Buen equilibrio para sesiones comunes. | No sustituye tokens CSRF en operaciones sensibles. |
SameSite=None; Secure |
Necesario para cookies de terceros o integraciones cross-site. | Debe llevar Secure. Úsalo solo si realmente lo necesitas. |
En WordPress, las cookies de autenticación suelen gestionarse internamente, pero el servidor, un plugin de seguridad o una capa de proxy pueden reforzar atributos en determinados escenarios. Cuidado con “arreglar” cookies a ciegas: una tienda WooCommerce, un SSO o un sistema multisitio pueden comportarse como relojes suizos… hasta que alguien cambia un engranaje con un martillo.
8. Cache-Control: privacidad también es no guardar de más
El rendimiento web nos ha enseñado a cachearlo todo: HTML, CSS, JS, imágenes, fuentes, respuestas de API. Y está bien. Pero cachear contenido privado en el lugar incorrecto es como dejar expedientes médicos en una cafetería porque “así se consultan más rápido”.
Para páginas públicas estáticas, puedes usar caché agresiva con versionado:
Cache-Control: public, max-age=31536000, immutable
Para áreas privadas, login, checkout, cuenta de usuario o datos personales:
Cache-Control: no-store, no-cache, must-revalidate, private
Pragma: no-cache
Expires: 0
no-store indica que la respuesta no debe almacenarse. private limita el almacenamiento a cachés privadas, aunque para contenido muy sensible conviene ser más restrictivo.
En WordPress y WooCommerce, revisa especialmente:
/wp-admin//wp-login.php- Páginas de carrito y checkout.
- Área “Mi cuenta”.
- Endpoints REST con datos privados.
- Paneles de membresía o LMS.
Encabezados recomendables según el tipo de proyecto
Más allá del mínimo, hay encabezados que pueden ser importantes en arquitecturas modernas, aplicaciones de alto riesgo o proyectos con integraciones complejas. Aquí el mapa se vuelve más interesante.
Cross-Origin-Opener-Policy, Cross-Origin-Embedder-Policy y Cross-Origin-Resource-Policy
Estos encabezados ayudan a aislar contextos de navegación y recursos entre orígenes. Son especialmente relevantes si necesitas cross-origin isolation, por ejemplo para usar ciertas APIs como SharedArrayBuffer de forma segura.
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp
Cross-Origin-Resource-Policy: same-origin
Pero cuidado: pueden romper recursos embebidos de terceros si no están preparados. Aquí la seguridad y la compatibilidad se miran como dos duelistas al amanecer. Antes de aplicarlos globalmente, prueba en staging.
COOPayuda a separar tu ventana de otras ventanas cross-origin.COEPexige que los recursos embebidos permitan explícitamente ser cargados.CORPindica quién puede cargar tus recursos.
Access-Control-Allow-Origin: CORS no es un escudo mágico
CORS merece una mención especial porque suele confundirse con seguridad del servidor. Access-Control-Allow-Origin no protege tus datos por sí mismo; regula qué orígenes pueden leer respuestas desde navegadores. Un atacante puede seguir haciendo solicitudes desde herramientas fuera del navegador si no hay autenticación adecuada.
Configuración peligrosa si se combina con credenciales:
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
De hecho, los navegadores no permiten esa combinación exacta con credenciales, pero muchas configuraciones dinámicas reflejan cualquier origen y añaden credenciales. Resultado: una puerta giratoria con alfombra roja.
Mejor:
Access-Control-Allow-Origin: https://app.tudominio.com
Access-Control-Allow-Credentials: true
Vary: Origin
Usa listas blancas explícitas, valida el encabezado Origin y añade Vary: Origin cuando la respuesta cambie según el origen.
Vary: Origin
Vary no es un encabezado de seguridad en sentido estricto, pero en CORS ayuda a evitar que una caché sirva a un origen una respuesta generada para otro. En entornos con CDN, proxies y APIs, puede marcar la diferencia entre una configuración limpia y una fuga sutil.
Vary: Origin
Encabezados obsoletos o que conviene evitar
No todo lo que suena a seguridad sigue siendo recomendable. La web envejece rápido; algunos encabezados que antes eran héroes hoy son estatuas con palomas encima.
| Encabezado | Estado actual | Recomendación |
|---|---|---|
X-XSS-Protection |
Obsoleto en navegadores modernos. | Preferible desactivarlo con 0 o no depender de él. Usa CSP. |
Public-Key-Pins / HPKP |
Obsoleto y peligroso. | No usar. Podía dejar dominios inaccesibles por errores de pinning. |
Expect-CT |
Obsoleto en la práctica tras la obligatoriedad de Certificate Transparency en Chrome. | No es necesario para la mayoría de sitios. |
X-Powered-By |
Expone tecnología, no aporta seguridad. | Eliminar o minimizar información. |
Server |
Puede revelar versión del servidor. | Reducir detalle si es posible, aunque no sustituye parcheo. |
Sobre X-XSS-Protection, algunos equipos aún lo añaden por costumbre:
X-XSS-Protection: 1; mode=block
Sin embargo, los filtros XSS integrados en navegadores han sido retirados o deshabilitados en muchos casos porque podían generar comportamientos inseguros. Si necesitas poner algo por compatibilidad, muchos especialistas prefieren:
X-XSS-Protection: 0
Lo importante: no lo cuentes como defensa principal.
Configuración recomendada de base para un sitio estándar
Para un sitio corporativo, blog profesional, WordPress básico o web de servicios sin funcionalidades extrañas, una base inicial podría ser:
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin
X-Frame-Options: SAMEORIGIN
Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=(), usb=()
Content-Security-Policy: default-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'self'; form-action 'self'; upgrade-insecure-requests
Pero no copies y pegues sin pensar. Una CSP demasiado estricta puede bloquear fuentes de Google, scripts de analítica, píxeles publicitarios, mapas, reCAPTCHA, vídeos incrustados, chats y pasarelas de pago. Una política demasiado laxa, en cambio, se convierte en un adorno: elegante, inútil, perfectamente auditable por alguien que no mira de cerca.
Ejemplos para Apache
En Apache, normalmente se usa el módulo mod_headers. Asegúrate de que esté habilitado.
<IfModule mod_headers.c>
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
Header always set X-Content-Type-Options "nosniff"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set Permissions-Policy "camera=(), microphone=(), geolocation=(), payment=(), usb=()"
Header always set Content-Security-Policy "default-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'self'; form-action 'self'; upgrade-insecure-requests"
</IfModule>
Para ocultar X-Powered-By en PHP:
expose_php = Off
Y en Apache, reducir firma del servidor:
ServerTokens Prod
ServerSignature Off
Ejemplos para Nginx
En Nginx, se usa add_header. Conviene añadir always para que los encabezados también aparezcan en respuestas de error.
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;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=(), payment=(), usb=()" always;
add_header Content-Security-Policy "default-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'self'; form-action 'self'; upgrade-insecure-requests" always;
Para áreas privadas:
location ~* ^/(wp-admin|wp-login\.php|mi-cuenta|checkout|carrito) {
add_header Cache-Control "no-store, no-cache, must-revalidate, private" always;
add_header Pragma "no-cache" always;
add_header Expires "0" always;
}
Nota: en Nginx, add_header tiene reglas de herencia que pueden sorprender. Si defines encabezados dentro de un bloque location, podrías sobrescribir los heredados. Es uno de esos detalles que parecen menores hasta que una auditoría te muestra que tus headers desaparecen justo en la página de login. Pequeñas tragedias de configuración.
WordPress: seguridad realista en un ecosistema lleno de plugins 🧩
WordPress no es inseguro por naturaleza, pero es extensible hasta el vértigo. Temas, constructores, plugins, shortcodes, scripts externos, AJAX, REST API, WooCommerce, formularios, píxeles, fuentes, CDN. Es una ciudad con muchos barrios y demasiadas llaves.
Para WordPress, los encabezados de seguridad pueden configurarse en:
- El servidor web: Apache, Nginx, LiteSpeed.
- El panel del hosting.
- Cloudflare u otro CDN/WAF.
- Plugins de seguridad.
- Código personalizado en el tema o un plugin propio.
¿Dónde conviene configurarlos?
Preferiblemente en el servidor o CDN. Así se aplican antes de que WordPress procese la solicitud y también pueden cubrir archivos estáticos, redirecciones y respuestas de error. Configurarlos mediante PHP puede funcionar para HTML, pero no siempre para imágenes, CSS, JS o errores generados por el servidor.
CSP en WordPress: paciencia, bisturí y registros
Una CSP estricta en WordPress puede ser difícil porque muchos plugins insertan scripts inline. Lo sensato:
- Auditar scripts externos actuales.
- Activar CSP en modo
Report-Only. - Recolectar violaciones durante varios días.
- Ajustar dominios permitidos.
- Eliminar plugins innecesarios o demasiado invasivos.
- Pasar a modo bloqueo gradualmente.
Una CSP más realista para un WordPress con recursos externos podría parecerse a esto —debes adaptarla—:
Content-Security-Policy: default-src 'self'; script-src 'self' https://www.googletagmanager.com https://www.google-analytics.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; img-src 'self' data: https:; connect-src 'self' https://www.google-analytics.com; frame-src https://www.youtube.com; object-src 'none'; base-uri 'self'; frame-ancestors 'self'; form-action 'self'; upgrade-insecure-requests
No es perfecta porque permite 'unsafe-inline' en estilos, algo frecuente por compatibilidad. El objetivo es mejorar progresivamente. La seguridad web rara vez se parece a encender una luz; se parece más a limpiar una casa vieja: levantas una alfombra y aparece otra historia.
Cloudflare y CDN: útiles, pero no mágicos ☁️
CDN y proxies como Cloudflare, Fastly, Akamai o BunnyCDN pueden añadir encabezados en el borde. Esto es útil porque centraliza políticas y evita tocar múltiples servidores. En Cloudflare, por ejemplo, puedes usar Rules, Transform Rules o configuraciones específicas de seguridad según el plan.
Ventajas:
- Aplicación rápida sin modificar código.
- Políticas consistentes para múltiples orígenes.
- Posibilidad de ajustar por ruta.
- Integración con WAF y caché.
Riesgos:
- Duplicar encabezados con valores contradictorios.
- Aplicar CSP global que rompe páginas específicas.
- Creer que el CDN protege también accesos directos al servidor de origen si este queda expuesto.
- Olvidar entornos staging, subdominios o APIs.
La regla de oro: define quién manda. Si el servidor y el CDN configuran los mismos encabezados, documenta la jerarquía. La seguridad sin documentación se convierte en arqueología para el próximo desarrollador.
Qué encabezados revisar en APIs
Las APIs no cargan páginas HTML, pero también necesitan atención. Para APIs JSON, algunos encabezados son especialmente relevantes:
Content-Type: application/json; charset=utf-8X-Content-Type-Options: nosniffCache-Control: no-storeen respuestas sensibles.- CORS estricto si la API se consume desde navegadores.
Vary: Originsi el CORS varía por origen.- Cookies con
Secure,HttpOnlyySameSitesi se usa autenticación basada en cookies.
Para APIs públicas con tokens Bearer, no confíes en CORS como control de acceso. Autenticación, autorización, rate limiting, validación y registros siguen siendo imprescindibles. CORS decide quién puede leer desde el navegador; no decide quién tiene derecho a los datos.
Herramientas para comprobar tus encabezados
No hace falta adivinar. Puedes comprobar los Security Headers con herramientas públicas y comandos locales.
Herramientas online
- Mozilla Observatory: evalúa encabezados, TLS, cookies y buenas prácticas.
- SecurityHeaders.com: ofrece una calificación rápida y clara.
- SSL Labs: excelente para revisar TLS/SSL, certificados y protocolos.
- Google Lighthouse: incluye auditorías útiles, aunque no sustituye una revisión de seguridad.
Con cURL
curl -I https://tudominio.com
Para seguir redirecciones:
curl -I -L https://tudominio.com
Para revisar una ruta concreta:
curl -I https://tudominio.com/wp-login.php
La revisión debe hacerse en varias rutas: home, login, panel, checkout, API, errores 404, archivos estáticos y subdominios. Más de una vez he visto sitios con una calificación perfecta en la portada y un agujero discreto en /admin. Como esas fachadas impecables de algunos pueblos donde la parte trasera da a un patio lleno de trastos.
Errores frecuentes al implementar Security Headers
1. Copiar políticas de otro sitio
La CSP de una aplicación bancaria no sirve necesariamente para una revista digital con publicidad programática. La configuración de un SaaS con React no encaja sin más en WordPress. Copiar encabezados sin entenderlos es como tomar medicación ajena porque ambos tienen fiebre.
2. Activar HSTS preload demasiado pronto
Antes de usar preload, verifica:
- HTTPS válido en dominio raíz.
- HTTPS válido en todos los subdominios.
- Redirección HTTP a HTTPS correcta.
max-agemínimo de 31536000.includeSubDomainsactivo.- Capacidad operativa para mantener HTTPS siempre.
3. Usar CSP con comodines excesivos
script-src * o default-src * reducen muchísimo la utilidad de CSP. A veces son necesarios temporalmente durante una migración, pero deben tener fecha de caducidad. La excepción permanente es la forma administrativa del abandono.
4. Olvidar páginas de error
Los encabezados deberían aplicarse también en 404, 500, redirecciones y respuestas generadas por el servidor. Por eso en Nginx y Apache es importante usar directivas que apliquen “always” cuando corresponda.
5. Duplicar encabezados contradictorios
Si Cloudflare envía una CSP y tu servidor envía otra, el navegador puede aplicar ambas o comportarse de forma inesperada según el encabezado. Lo mismo ocurre con X-Frame-Options, CORS o Cache-Control.
6. Ignorar terceros
Google Analytics, Tag Manager, Meta Pixel, YouTube, Stripe, PayPal, reCAPTCHA, mapas, chatbots, fuentes externas, CDN de librerías. Cada tercero amplía la superficie de ataque y complica CSP. No se trata de vivir en una cueva, pero sí de saber quién entra a casa.
Política mínima recomendada por tipo de sitio
| Tipo de sitio | Encabezados mínimos recomendados | Notas |
|---|---|---|
| Blog o web corporativa simple | HSTS, CSP básica, X-Content-Type-Options, Referrer-Policy, X-Frame-Options/frame-ancestors, Permissions-Policy | Revisar scripts de analítica, fuentes y formularios. |
| WordPress con plugins | Los anteriores + cookies seguras + CSP gradual en Report-Only | Especial cuidado con constructores visuales, formularios y plugins de marketing. |
| WooCommerce o e-commerce | Todos los mínimos + Cache-Control privado en checkout/cuenta + cookies robustas | Validar pasarelas de pago, iframes y redirecciones externas. |
| SaaS o aplicación con login | Todos + CSP con nonces/hashes + COOP/COEP/CORP si aplica + CORS estricto | Integrar headers en pipeline CI/CD y pruebas automatizadas. |
| API privada | X-Content-Type-Options, Cache-Control, CORS estricto, Vary: Origin, cookies seguras si aplica | No confiar en CORS como autenticación. |
| Administración pública o sector regulado | Política completa documentada, auditoría periódica, HSTS fuerte, CSP rigurosa, registros | Alinear con ENS, ISO 27001, OWASP ASVS o requisitos internos. |
¿Cómo priorizar si partes de cero?
Si tu sitio no tiene ningún encabezado de seguridad, no intentes resolverlo todo en una tarde heroica. La heroicidad en producción suele dejar tickets al día siguiente.
- Confirma HTTPS completo: certificado válido, redirecciones limpias, sin contenido mixto.
- Añade
X-Content-Type-Options: bajo riesgo, alto beneficio. - Añade
Referrer-Policy: normalmente no rompe nada. - Añade protección contra iframes:
X-Frame-Optionsoframe-ancestors. - Configura HSTS progresivamente: empieza con
max-agebajo, luego aumenta. - Implementa
Permissions-Policy: bloquea APIs que no usas. - Diseña CSP en modo Report-Only: observa, ajusta y luego bloquea.
- Revisa cookies y caché: especialmente si hay login, pagos o datos personales.
- Automatiza pruebas: para que los encabezados no desaparezcan en el próximo despliegue.
Checklist rápida para producción ✅
- HTTPS activo en todo el sitio.
- Redirección HTTP → HTTPS sin cadenas innecesarias.
Strict-Transport-Securityconfigurado con cuidado.X-Content-Type-Options: nosniff.Referrer-Policydefinida.- Protección anti-clickjacking con
frame-ancestorsoX-Frame-Options. Permissions-Policyrestrictiva.- CSP probada, preferiblemente sin comodines peligrosos.
- Cookies con
Secure,HttpOnlyySameSite. Cache-Controladecuado para contenido privado.- Sin encabezados obsoletos usados como defensa principal.
- Headers presentes también en errores, redirecciones y rutas sensibles.
Security Headers y rendimiento: ¿afectan la velocidad?
En términos generales, los encabezados de seguridad tienen un impacto mínimo en rendimiento. Son texto. Apenas pesan. Lo que sí puede afectar indirectamente es una política CSP mal planteada que bloquee recursos, genere errores o impida optimizaciones.
HSTS incluso puede mejorar la experiencia al evitar intentos iniciales por HTTP después de quedar registrado en el navegador. upgrade-insecure-requests ayuda durante migraciones a HTTPS, aunque no debe usarse como sustituto de corregir URLs internas.
La verdadera relación entre seguridad y rendimiento aparece en otro plano: menos scripts de terceros, menor superficie de ataque, menos dependencias, menos llamadas externas. Un sitio sobrio suele ser más rápido y más seguro. Antítesis feliz: cuanto menos ruido, más defensa.
Security Headers no sustituyen otras medidas
Sería cómodo pensar que unos encabezados bien puestos bastan. No basta. Ayudan mucho, pero no reemplazan:
- Actualizaciones de CMS, temas, plugins y dependencias.
- Validación y sanitización de entradas.
- Escape correcto de salidas.
- Autenticación multifactor.
- Principio de mínimo privilegio.
- Copias de seguridad verificadas.
- WAF bien configurado.
- Monitorización de logs.
- Protección contra fuerza bruta.
- Revisión de permisos de archivos.
- Gestión segura de secretos y claves API.
Los encabezados son una muralla, no el reino completo. Y una muralla con puertas mal vigiladas solo sirve para dar sombra.
Una configuración más avanzada como punto de partida
Para una aplicación web moderna con control sobre el frontend y backend, podrías aspirar a algo más estricto:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=(), usb=(), interest-cohort=()
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Resource-Policy: same-origin
Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-{RANDOM}'; style-src 'self' 'nonce-{RANDOM}'; img-src 'self' data: https:; font-src 'self'; connect-src 'self' https://api.tudominio.com; frame-ancestors 'none'; object-src 'none'; base-uri 'self'; form-action 'self'; upgrade-insecure-requests
Si necesitas aislamiento completo:
Cross-Origin-Embedder-Policy: require-corp
Pero solo tras verificar que tus recursos externos envían permisos adecuados. De lo contrario, verás cómo partes del sitio desaparecen con la elegancia cruel de una marea que se lleva castillos de arena.
Preguntas frecuentes
¿Necesito todos los encabezados si mi sitio solo es informativo?
No todos, pero sí una base. Incluso un sitio informativo puede sufrir XSS por plugins, formularios, scripts de terceros o malas configuraciones. Como mínimo: HSTS si usas HTTPS correctamente, X-Content-Type-Options, Referrer-Policy, protección contra iframes, Permissions-Policy y una CSP básica.
¿Puedo configurar Security Headers desde un plugin de WordPress?
Sí, pero no siempre es lo ideal. Un plugin puede funcionar para respuestas generadas por WordPress, aunque tal vez no cubra archivos estáticos, errores del servidor o determinadas redirecciones. Si puedes, configura en servidor o CDN. Si no, un buen plugin es mejor que nada, siempre que se pruebe bien.
¿Una buena puntuación en SecurityHeaders.com significa que estoy seguro?
No necesariamente. Significa que ciertos encabezados están presentes y tienen una forma aceptable. Es útil, pero no mide toda la seguridad: lógica de negocio, vulnerabilidades en plugins, contraseñas débiles, permisos mal configurados, inyecciones SQL, exposición de backups o APIs sin control.
¿CSP puede romper mi sitio?
Sí. Por eso conviene usar Content-Security-Policy-Report-Only antes de bloquear. CSP es potente precisamente porque restringe. Y todo lo que restringe puede cortar algo que alguien daba por sentado.
¿Debo eliminar el encabezado Server?
Reducir información expuesta es buena práctica, pero no es una defensa fuerte. Ocultar que usas Nginx o Apache no protege un servidor sin parches. La discreción ayuda; el mantenimiento salva.
¿Qué hago con sitios que necesitan ser embebidos en iframes?
Usa frame-ancestors en CSP y permite solo dominios específicos. Evita permitir *. Documenta quién puede embeber tu sitio y por qué.
La parte humana: seguridad como hábito, no como ceremonia
Hace años, en una migración pequeña —de esas que en teoría se resuelven antes del café— encontré un panel administrativo servido por HTTPS, protegido con contraseña fuerte y, sin embargo, embebible desde cualquier dominio. Nadie lo había notado. No había drama visible. No sonaban alarmas. La vulnerabilidad estaba allí, quieta, como una gotera detrás de una pared recién pintada.
Eso tienen los encabezados HTTP: pertenecen al reino de lo invisible. No cambian el hero banner, no mejoran el logo, no hacen que el cliente diga “qué bonito quedó el sitio”. Pero cuando faltan, el navegador pierde instrucciones esenciales. Y cuando están bien puestos, muchas amenazas encuentran la puerta cerrada antes incluso de empezar la conversación.
La seguridad web madura no consiste en llenar el servidor de amuletos técnicos. Consiste en entender el riesgo, aplicar controles adecuados, medir, ajustar y volver a revisar. Es menos épica que una película de hackers; más parecida a revisar cerraduras antes de dormir. Aburrida, tal vez. Eficaz, sin duda.
Resumen práctico: qué encabezados deberías tener
Si administras un servidor, una web en WordPress, una tienda online o una aplicación profesional, estos son los encabezados que deberías considerar como base mínima:
- Imprescindible
Strict-Transport-Security, si todo funciona correctamente con HTTPS. - Imprescindible
Content-Security-Policy, al menos en una versión básica y preferiblemente evolucionada. - Imprescindible
X-Content-Type-Options: nosniff. - Imprescindible
Referrer-Policy: strict-origin-when-cross-origino una opción más restrictiva. - Imprescindible
X-Frame-Optionso, mejor,frame-ancestorsen CSP. - Muy recomendable
Permissions-Policypara limitar APIs del navegador. - Crítico con sesionesCookies con
Secure,HttpOnlyySameSite. - Crítico en datos privados
Cache-Controladecuado para evitar almacenamiento indebido. - Según arquitectura
COOP,COEPyCORPpara aislamiento avanzado. - Con cuidadoCORS estricto y bien documentado en APIs.
El servidor perfecto no existe. El sitio invulnerable tampoco. Pero entre la perfección imposible y el abandono cómodo hay un territorio profesional donde se configuran encabezados, se prueban rutas, se reducen permisos y se documentan decisiones. Ahí vive la seguridad real: no en el gesto grandilocuente, sino en la suma de pequeñas órdenes bien dadas.
Y el navegador, que no tiene intuición ni memoria moral, agradece esas órdenes. Obedece. Bloquea. Restringe. Protege. A veces, unas líneas en una respuesta HTTP son la diferencia entre una página que simplemente carga y una página que sabe defenderse. 🚀