Configurar CSP y HSTS en Azure App Service paso a paso

Los equipos de seguridad exigen cada vez más que las aplicaciones web adopten cabeceras defensivas. Dos de las más críticas son Content Security Policy (CSP) y HTTP Strict Transport Security (HSTS). Este artículo explica, paso a paso, cómo habilitarlas en cualquier arquitectura típica que se ejecute sobre Azure.

Índice

Por qué CSP y HSTS importan en la nube de Azure

CSP mitiga cross‑site scripting, click‑jacking y la inyección de recursos maliciosos al restringir las fuentes válidas de scripts, hojas de estilo, imágenes y otros activos.
HSTS obliga a los navegadores a usar siempre TLS, eliminando la posibilidad de ataques de downgrade y de man‑in‑the‑middle que aprovechen solicitudes HTTP limpias.

Al combinar ambas directivas refuerzas la superficie defensiva, obtienes mejor puntuación en auditorías y cumples los requisitos de marcos como ISO 27001, NIST 800‑53 o el Esquema Nacional de Seguridad.

Resumen del escenario inicial

Pregunta original.
Un administrador de una aplicación en Azure, publicada con un dominio personalizado, desea añadir CSP y HSTS pero no localiza la opción en el Portal.

El problema radica en que las cabeceras no se exponen mediante un interruptor gráfico. Deben inyectarse en la capa correcta de la pila (servidor, proxy o código). A continuación se muestra una visión condensada de dónde y cómo hacerlo.

Dónde insertar los encabezados

Capa donde puedes insertar los encabezadosCómo añadir Strict‑Transport‑Security y Content‑Security‑PolicyComentarios
Azure App Service (Windows)Incluye las directivas en web.config dentro de <system.webServer><httpProtocol><customHeaders>:
<add name="Strict-Transport-Security" value="max-age=31536000; includeSubDomains; preload" />
<add name="Content-Security-Policy" value="default-src 'self'; script-src 'self'; object-src 'none'; frame-ancestors 'none'" />
Requiere reiniciar la aplicación.
Azure App Service (Linux o contenizada)Añade las cabeceras en nginx.conf, apache.conf o tu Dockerfile. Ejemplo Nginx:
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload";
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; object-src 'none'; frame-ancestors 'none'";
Debes reconstruir la imagen y hacer az webapp restart.
Middleware de la aplicación.NET — app.UseHsts() y app.UseCsp() (NWebsec).
Node/Express — helmet.hsts() y helmet.contentSecurityPolicy().
Ideal si controlas el código fuente y prevés cambios de hosting.
Azure Front Door, Application Gateway o CDNCrea un Rule Set o Custom rule que agregue o reescriba cabeceras en la respuesta antes de enviarla al cliente.Un único punto para varios back‑ends; útil con microservicios.
Redirección HTTPS + HSTSActiva HTTPS Only en App Service o la redirección 308 en Front Door.
Sin redirección forzada, HSTS pierde efectividad.
HSTS solo se aplica después de la primera carga HTTPS exitosa.
Pre‑carga HSTS (opcional)Una vez estable y con HTTPS en todos los subdominios, registra el dominio en hstspreload.org.Necesitas la directiva preload y un max-age ≥ 31536000.

Implementación paso a paso por escenario

App Service sobre Windows

  1. Abre el explorador de archivos de Kudu (https://<tu‑sitio>.scm.azurewebsites.net) y navega al directorio raíz.
  2. Edita o crea web.config con el bloque: <configuration> <system.webServer> <httpProtocol> <customHeaders> <add name=”Strict-Transport-Security” value=”max-age=31536000; includeSubDomains; preload” /> <add name=”Content-Security-Policy” value=”default-src ‘self’; script-src ‘self’; object-src ‘none’; frame-ancestors ‘none'” /> </customHeaders> </httpProtocol> </system.webServer> </configuration>
  3. Guarda, reinicia la aplicación desde el Portal o con az webapp restart.
  4. Valida con curl ‑I https://tudominio.com que ambas cabeceras aparezcan.

App Service sobre Linux o contenizada

  1. Añade las cabeceras en la sección server de tu nginx.conf o en un archivo .conf colocado en /etc/nginx/conf.d.
  2. Ejemplo completo: server { listen 80; return 301 https://$servername$requesturi; } server { listen 443 ssl; … add_header Strict-Transport-Security “max-age=31536000; includeSubDomains; preload”; add_header Content-Security-Policy “default-src ‘self’; script-src ‘self’; object-src ‘none’; frame-ancestors ‘none'”; }
  3. Reconstruye la imagen (docker build) y publícala de nuevo con tu pipeline o con az acr build.
  4. Reinicia la instancia y comprueba.

Middleware de la aplicación (.NET ejemplo)

  1. Añade el paquete NuGet NWebsec.AspNetCore.Core.
  2. En Program.cs: if (!app.Environment.IsDevelopment()) { app.UseHsts(h => h.MaxAge(365).IncludeSubdomains().Preload()); } app.UseCsp(c => c .DefaultSources(s => s.Self()) .ScriptSources(s => s.Self()) .ObjectSources(s => s.None()) .FrameAncestors(s => s.None()) );
  3. Publica con tu pipeline. Las cabeceras se agregarán en tiempo de ejecución.

Azure Front Door / Application Gateway

  1. Crea un nuevo Rule Set y asígnalo al front‑end correspondiente.
  2. Añade una regla con la acción “Modify Response Header”.
  3. Claves y valores recomendados:
    • Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
    • Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none'; frame-ancestors 'none'
  4. Guarda y prueba. Todas las respuestas inmediatamente heredarán las cabeceras, sin tocar los back‑ends.

Habilitar HTTPS Only y redirección 308

HSTS no impide que un usuario introduzca http:// manualmente la primera vez. Por eso es esencial:

  • En App Service: Custom domains > HTTPS Only = On.
  • En Front Door: regla de reescritura 301/308 que dirija todo el tráfico HTTP a HTTPS.

Estrategia de pre‑carga HSTS

Solo realiza el alta en la lista de pre‑carga cuando cumplas todos los requisitos:

  1. Todas las rutas y subdominios responden exclusivamente por HTTPS.
  2. El certificado TLS no está a punto de caducar (se aconseja >60 días de validez en el momento de la solicitud).
  3. El encabezado incluye max-age=31536000, includeSubDomains y la directiva preload.

La eliminación de un dominio de la lista puede tardar meses, así que valida exhaustivamente antes de enviar la solicitud.

Introducir CSP sin romper producción

En aplicaciones grandes, aplicar una CSP restrictiva de golpe puede bloquear recursos legítimos y romper la interfaz. Usa el modo Content-Security-Policy-Report-Only para registrar violaciones sin imponerlas:

add_header Content-Security-Policy-Report-Only "default-src 'self'; report-uri /csp-report-endpoint";

Revisa los reportes, ajusta la política y, cuando ya no se registren eventos no deseados, cambia a Content-Security-Policy definitiva.

Automatización con IaC y CI/CD

  • ARM/Bicep: define bloques siteConfig.customHeaders o frontdoor/routeConfiguration/responseHeaders.
  • Terraform: módulo azurermappservice incluye siteconfig => cors.customheaders; Front Door con azurermcdnfrontdoorrouteresponseheaderaction.
  • GitHub Actions / Azure Pipelines: añade tareas de validación curl -I y falla el build si falta alguna cabecera.

Pruebas, monitoreo y mantenimiento

  1. Integra OWASP ZAP, Burp o Microsoft Security DevOps en tu pipeline para verificar CSP/HSTS en cada despliegue.
  2. Activa alertas en Azure Monitor mediante Log Analytics para detectar respuestas sin cabeceras.
  3. Revisa periódicamente los dominios de terceros listados en CSP; los servicios externos cambian y necesitan ajustes.
  4. Renueva tus certificados antes de los 30 días previos al vencimiento; de lo contrario la combinación de HSTS con un certificado caducado provocará bloqueos totales.

Resumen final

Configurar CSP y HSTS en Azure no depende de un botón mágico sino de elegir correctamente la capa donde insertar cada cabecera: servidor, código o proxy. Con la tabla de referencia y los pasos detallados podrás cumplir controles de ciberseguridad de forma repetible, auditable y apta para DevSecOps. Empieza en modo report‑only, valida, automatiza y, cuando todo esté estable, activa la política estricta.

Índice