Ir directamente al contenido

Ajustes de cookies

Elija por tipo qué cookies permite. Puede cambiar su elección en cualquier momento en Ajustes de cookies, al pie de cada página. Declaración de privacidad

Necesarias

Siempre activadas

Necesarias para iniciar sesión, conservar su carrito y recordar sus preferencias. Siempre están activadas.

¿Qué cookies?
  • weboke_sessie, weboke_klant, weboke_remember: su sesión y mantener la sesión iniciada
  • weboke_basket: su carrito
  • wkBtwIncl: mostrar los precios con o sin IVA
  • wok_cookies: su elección de cookies, 12 meses

Mide qué anuncio lleva a una visita o a un pedido, para no pagar por anuncios que no sirven de nada.

¿Qué cookies?
  • Google Ads a través de Google Tag Manager (_gcl_au, _gcl_aw), hasta 90 días
  • OpenAI Ads, anuncios en ChatGPT
  • wok_aff: a través de qué socio llegó a nosotros (programa de afiliados), 60 días

4,6

País e idioma

Cada país tiene su propio sitio, con los precios y el IVA de ese país.

Ver

Módulo 7 · 7.4

Caddy, HSTS y security.txt

Módulo 7: Dominio, servidor web y https · Tiempo de lectura: 12 minutos

Objetivo de aprendizaje: Después de esta lección podrá usar Caddy como servidor web sencillo con https automático, configurar HSTS y las cabeceras de seguridad más importantes (en Caddy y nginx) sin dejar su sitio inaccesible, y publicar un security.txt válido.

Conceptos clave: Caddy, Caddyfile, https automático, reverse_proxy, file_server, header, HSTS (Strict-Transport-Security), max-age, includeSubDomains, preload, X-Content-Type-Options, frame-ancestors, Referrer-Policy, security.txt, Contact, Expires, /.well-known/

Caddy: https sin preocupaciones

En las lecciones 7.2 y 7.3 creó con nginx y certbot un sitio con https. Son dos programas, unos cuantos archivos y un temporizador. Caddy lo hace todo en uno: es un servidor web con un cliente ACME integrado. Si un nombre figura en la configuración, apunta al servidor y los puertos 80 y 443 son accesibles, Caddy obtiene por sí mismo un certificado, lo renueva a tiempo y redirige http a https.

Caddy está en el repositorio de paquetes de Debian y Ubuntu (en una versión algo más antigua); sus creadores también ofrecen un repositorio apt propio con la versión más reciente, con su propia clave y Signed-By, como en la lección 4.1. En el módulo 9, Caddy se ejecuta como contenedor para sus servicios Docker (lección 9.4). Aquí lo usa como un servicio normal.

anna@web1:~$ sudo apt install caddy
anna@web1:~$ systemctl status caddy

Use nginx o Caddy en los puertos 80 y 443, pero no ambos: solo un programa puede escuchar en un puerto.

El Caddyfile

La configuración está en /etc/caddy/Caddyfile. Un sitio estático y una aplicación detrás de un proxy inverso:

example.com, www.example.com {
	root * /var/www/example.com
	file_server
	encode zstd gzip
}

app.example.com {
	reverse_proxy 127.0.0.1:3000
}

Eso es todo. Caddy escucha automáticamente en IPv4 e IPv6, solicita certificados para los tres nombres, redirige http a https y, con reverse_proxy, transmite por sí mismo las cabeceras X-Forwarded-For y X-Forwarded-Proto (lo que en nginx hizo a mano, lección 7.2).

Probar y recargar funciona igual que con nginx:

anna@web1:~$ caddy validate --config /etc/caddy/Caddyfile
Valid configuration
anna@web1:~$ sudo systemctl reload caddy
anna@web1:~$ sudo journalctl -u caddy -f

En el journal verá cómo se obtienen los certificados. Si algo falla, allí aparece el motivo: normalmente el mismo que con certbot (puerto 80 cerrado, el nombre apunta a otro sitio, IPv6 roto; lección 7.3).

HSTS: que el navegador recuerde que es https

Redirigir de http a https tiene un momento débil: la primerísima petición por http todavía viaja sin cifrar. Alguien en la misma red puede interceptarla y mantener al visitante en http. HSTS (HTTP Strict Transport Security, RFC 6797) lo soluciona. Su sitio envía por https esta cabecera:

Strict-Transport-Security: max-age=31536000

El navegador recuerda entonces durante un año (31.536.000 segundos) que a este nombre solo se puede acceder por https. Si más adelante el visitante escribe http://, el navegador lo convierte por sí mismo en https, antes de que nada pase por la red. El navegador ignora una cabecera HSTS que llega por http; solo cuenta por https.

Tiene una contrapartida. Si un navegador ha memorizado HSTS y ve un error de certificado (caducado, nombre incorrecto), el visitante no recibe ningún botón para continuar de todos modos. Su sitio queda entonces inaccesible para esos visitantes hasta que el certificado sea correcto. Por eso:

  1. Active HSTS solo cuando https funcione en todas partes y la renovación sea automática (lección 7.3).
  2. Empiece con un max-age corto, por ejemplo un día (86400), y auméntelo por etapas hasta un año.
  3. Tenga cuidado con includeSubDomains: se aplica a todos los subdominios, también a un subdominio antiguo con un dispositivo o servicio sin certificado válido.
  4. preload solicita la inclusión en una lista integrada en los navegadores (hstspreload.org). Para ello exigen, entre otras cosas, un max-age de al menos un año, includeSubDomains y https en todos los subdominios. Salir de la lista tarda meses. Hágalo solo si está seguro de que todo el dominio será https para siempre.

Las demás cabeceras de seguridad

Además de HSTS, hay unas cuantas cabeceras que ayudan mucho con poco esfuerzo:

CabeceraContra qué protegeValor para empezar
X-Content-Type-Optionsel navegador intenta adivinar qué es un archivo, de modo que una "imagen" subida puede ejecutarse como scriptnosniff
Content-Security-Policy: frame-ancestors (o la más antigua X-Frame-Options)clickjacking: otro sitio carga su página de forma invisible en un marcoframe-ancestors 'self' (o X-Frame-Options: SAMEORIGIN)
Referrer-Policyla dirección de su página (con términos de búsqueda o números de pedido) se filtra a otros sitiosstrict-origin-when-cross-origin

Un Content-Security-Policy completo (qué scripts y estilos pueden cargarse) se hace a medida para cada sitio y queda fuera de este curso; empiece solo con frame-ancestors.

En Caddy las configura con la directiva header dentro del bloque de un sitio:

example.com, www.example.com {
	root * /var/www/example.com
	file_server
	header {
		Strict-Transport-Security "max-age=31536000"
		X-Content-Type-Options "nosniff"
		Content-Security-Policy "frame-ancestors 'self'"
		Referrer-Policy "strict-origin-when-cross-origin"
		-Server
	}
}

Caddy no configura HSTS ni estas cabeceras por sí mismo; por tanto, tiene que añadirlas usted. -Server elimina la cabecera Server. En la lección 9.4 añadirá en el mismo tipo de bloque su propia cabecera X-Weboke-Cursus para el ejercicio.

En nginx pone las mismas líneas en el bloque server del puerto 443:

add_header Strict-Transport-Security "max-age=31536000" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Content-Security-Policy "frame-ancestors 'self'" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;

always hace que también se envíen con las páginas de error. Cuidado con una trampa conocida de nginx: si dentro de un bloque location hay un solo add_header propio, las líneas add_header del bloque server dejan de aplicarse a esa location. Por eso, compruebe siempre el resultado:

anna@laptop:~$ curl -sI https://example.com | grep -iE 'strict|nosniff|frame|referrer'
strict-transport-security: max-age=31536000
x-content-type-options: nosniff
content-security-policy: frame-ancestors 'self'
referrer-policy: strict-origin-when-cross-origin

security.txt: así pueden avisarle de una vulnerabilidad

Supongamos que alguien encuentra una vulnerabilidad en su servidor, como una carpeta abierta o un servicio desactualizado. ¿Cómo sabe esa persona a quién avisar? Para eso existe security.txt (RFC 9116): un pequeño archivo de texto en una ubicación fija, https://<jouwdomein>/.well-known/security.txt.

Contact: mailto:security@example.com
Expires: 2027-10-31T23:00:00Z
Preferred-Languages: nl, en
Canonical: https://example.com/.well-known/security.txt

Las reglas:

  • Contact es obligatorio: una dirección mailto:, https:// o tel: a la que lleguen los avisos. Use una dirección que alguien lea de verdad.
  • Expires es obligatorio y solo puede aparecer una vez: la fecha a partir de la cual el archivo se considera obsoleto. El RFC recomienda una fecha dentro de un año. Así no queda publicado un archivo con una dirección olvidada hace tiempo. Anote en su agenda cuándo debe renovarlo.
  • Preferred-Languages, Canonical y Policy (un enlace a su política de avisos) son opcionales.
  • El archivo debe servirse por https, como texto plano (text/plain, UTF-8). La ubicación antigua /security.txt se permite como extra, pero /.well-known/ tiene prioridad.

Colocarlo en un sitio estático:

anna@web1:~$ sudo mkdir -p /var/www/example.com/.well-known
anna@web1:~$ sudoedit /var/www/example.com/.well-known/security.txt
anna@laptop:~$ curl -sI https://example.com/.well-known/security.txt | grep -i content-type
content-type: text/plain; charset=utf-8

Si en nginx usa la regla general location ~ /\. { deny all; } de la lección 7.2, añada antes una excepción: location ^~ /.well-known/ { }. Para una aplicación detrás de un proxy inverso, en Caddy puede hacer que la ruta /.well-known/security.txt apunte a un archivo con un bloque handle y file_server.

Un error frecuente: un sitio o una aplicación que responde a cualquier ruta desconocida con la página principal y el código 200. Entonces security.txt "existe", pero es HTML. Compruebe, por tanto, también el contenido.

En AlmaLinux y Rocky Linux

Allí Caddy se obtiene del repositorio de sus creadores o de EPEL/COPR. Igual que con nginx, SELinux debe permitir un proxy inverso (setsebool -P httpd_can_network_connect 1). El Caddyfile y las cabeceras son los mismos.

Resumen

  • Caddy se encarga por sí mismo de los certificados, su renovación y la redirección a https; reverse_proxy transmite automáticamente las cabeceras correctas.
  • HSTS hace que los navegadores recuerden que su sitio es solo https; aumente max-age poco a poco, tenga cuidado con includeSubDomains y mucho cuidado con preload.
  • Configure además X-Content-Type-Options: nosniff, frame-ancestors 'self' y una Referrer-Policy; en Caddy con header, en nginx con add_header ... always, y compruébelo con curl -I.
  • security.txt está en /.well-known/security.txt, por https, como texto plano, con Contact obligatorio y un único Expires dentro de un año.

Cuestionario

1. ¿Por qué ayuda HSTS si ya redirige http a https?



2. Configura HSTS con max-age=31536000; includeSubDomains. Una semana después resulta que camera.example.com no tiene un certificado válido. ¿Qué notan los visitantes que ya habían visitado su sitio?



3. ¿Qué campos son obligatorios en un security.txt?



4. En nginx ha puesto las cabeceras de seguridad en el bloque server, pero para /api/ no se envían. En el bloque location /api/ hay un add_header propio. ¿Qué ocurre?



5. ¿Qué debe hacer antes de añadir preload a su cabecera HSTS?



Ejercicio

Ejercicio Z7.4: HSTS, cabeceras y security.txt. Configure para su sitio HSTS (al menos 180 días, después de que https lleve un tiempo funcionando bien), X-Content-Type-Options: nosniff y frame-ancestors 'self' (o X-Frame-Options), y publique un security.txt con Contact y un Expires dentro de un año. Introduzca su nombre de host. El programa obtiene https://<hostnaam>/ y comprueba las cabeceras, y obtiene https://<hostnaam>/.well-known/security.txt y comprueba los campos. No guarda nada salvo el resultado y la fecha de Expires.

Ejercicio Z7.4: HSTS, cabeceras y security.txt

Solo para alumnos inscritos. Obtenemos https://<naam>/ y /.well-known/security.txt (solo GET).




No guardamos lo que escriba ni lo que encontremos. Su navegador recuerda sus respuestas y si ha superado el ejercicio. Si ha iniciado sesión, en Mis cursos solo guardamos que el ejercicio estaba (casi) correcto; allí también puede eliminarlo.

Para saber más

Un momento…

Configure sus dominios

Configure para cada dominio los servidores de nombres, la vinculación a su hosting y quién será el titular.

Cargando sus dominios…