VoryngVoryng
VoryngVoryng

Cómo configurar las cabeceras de seguridad en Apache

Apache es el caso más sencillo: se resuelve con un bloque en el .htaccess. Lo que suele fallar no es el bloque, son dos detalles del propio Apache que hacen que las cabeceras no lleguen a aplicarse.

Actualizada el 6 de octubre de 2026

El bloque

Pégalo al final del .htaccess de la raíz del sitio. Si tu hosting te da acceso al vhost, es mejor sitio todavía: el .htaccess se relee en cada petición y el vhost no.

.htaccess
<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 X-Frame-Options "SAMEORIGIN"
  Header always set Referrer-Policy "strict-origin-when-cross-origin"
  Header always set Permissions-Policy "camera=(), microphone=(), geolocation=()"
</IfModule>

El envoltorio <IfModule> evita que el sitio devuelva un 500 si mod_headers no está cargado. Es una red de seguridad, no una solución: si el módulo no está, las cabeceras simplemente no se aplican y no te enteras.

Comprueba que mod_headers está activo

Es el motivo número uno de que el bloque no haga nada. Si tienes acceso por SSH:

apachectl -M | grep headers

Si devuelve headers_module (shared), está activo. Si no devuelve nada, hay que cargarlo:

a2enmod headers && systemctl reload apache2

Si el .htaccess se ignora

Apache solo lee el .htaccess si el vhost lo permite. Si has puesto el bloque, mod_headers está activo y aun así no pasa nada, es esto:

vhost
<Directory /var/www/tu-sitio>
  AllowOverride All
</Directory>

Con AllowOverride None el fichero se ignora por completo, en silencio. En hosting compartido viene permitido por defecto.

Content-Security-Policy, aparte

La CSP no se puede copiar y pegar: depende de qué scripts, estilos y fuentes carga tu sitio. Una CSP copiada rompe la web o no protege nada. El orden correcto es medir primero:

.htaccess — solo para medir, no bloquea nada
Header always set Content-Security-Policy-Report-Only "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'"

Report-Only no bloquea: solo anota en la consola del navegador lo que habría bloqueado. Navega tu sitio unos días, mira la consola, añade a la política los orígenes legítimos que aparezcan, y solo entonces cambia la cabecera a Content-Security-Policy.

Verificar

Desde tu terminal, que es lo más directo y no miente:

curl -sI https://tu-dominio.com | grep -i -E "strict-transport|x-frame|x-content-type|referrer-policy|permissions-policy"

Comprueba también una respuesta de error, que es lo que el always arregla:

curl -sI https://tu-dominio.com/esta-ruta-no-existe | grep -i x-frame
  • Si la segunda orden no devuelve nada, te falta el always.
  • Si ninguna devuelve nada, es mod_headers o AllowOverride.
  • securityheaders.com/?q=tu-dominio.com te da la misma información con nota de la A a la F, útil para enseñárselo al cliente.

Otras guías

Cómo configurar las cabeceras de seguridad en Apache | Voryng