Módulo 7 · 7.4
Caddy, HSTS e security.txt
Módulo 7: Domínio, servidor web e https · Tempo de leitura: 12 minutos
Objetivo de aprendizagem: Depois desta lição, será capaz de utilizar o Caddy como servidor web simples com https automático, definir o HSTS e os principais cabeçalhos de segurança (no Caddy e no nginx) sem tornar o seu site inacessível, e publicar um security.txt válido.
Conceitos-chave: 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 sem preocupações
Nas lições 7.2 e 7.3 criou um site com https utilizando o nginx e o certbot. São dois programas, alguns ficheiros e um temporizador. O Caddy faz tudo num só: é um servidor web com um cliente ACME integrado. Se um nome constar da configuração, apontar para o servidor e as portas 80 e 443 estiverem acessíveis, o Caddy obtém ele próprio um certificado, renova-o a tempo e redireciona http para https.
O Caddy está disponível no repositório de pacotes do Debian e do Ubuntu (numa versão um pouco mais antiga); os criadores oferecem também um repositório apt próprio com a versão mais recente, com uma chave própria e Signed-By, tal como na lição 4.1. No módulo 9, o Caddy é executado como contentor para os seus serviços Docker (lição 9.4). Aqui, utiliza-o como um serviço normal.
anna@web1:~$ sudo apt install caddy
anna@web1:~$ systemctl status caddyUtilize o nginx ou o Caddy nas portas 80 e 443, não ambos: apenas um programa pode escutar numa porta.
O Caddyfile
A configuração encontra-se em /etc/caddy/Caddyfile. Um site estático e uma aplicação por detrás de um 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
}É tudo. O Caddy escuta automaticamente em IPv4 e IPv6, pede certificados para os três nomes, redireciona http para https e, com reverse_proxy, transmite automaticamente os cabeçalhos X-Forwarded-For e X-Forwarded-Proto (o que no nginx fazia manualmente, lição 7.2).
Testar e recarregar faz-se como no nginx:
anna@web1:~$ caddy validate --config /etc/caddy/Caddyfile
Valid configuration
anna@web1:~$ sudo systemctl reload caddy
anna@web1:~$ sudo journalctl -u caddy -fNo journal pode ver a obtenção dos certificados. Se algo correr mal, o motivo aparece aí: normalmente o mesmo que no certbot (porta 80 fechada, nome a apontar para outro sítio, IPv6 com problemas; lição 7.3).
HSTS: fazer o navegador lembrar-se de que é https
O redirecionamento de http para https tem um momento fraco: o primeiríssimo pedido por http ainda segue sem cifra. Alguém na mesma rede pode intercetá-lo e manter o visitante em http. O HSTS (HTTP Strict Transport Security, RFC 6797) resolve isso. O seu site envia, por https, este cabeçalho:
Strict-Transport-Security: max-age=31536000O navegador memoriza então, durante um ano (31.536.000 segundos), que este nome só pode ser utilizado por https. Se o visitante escrever mais tarde http://, o próprio navegador converte o endereço para https, antes de qualquer dado passar pela rede. Um cabeçalho HSTS recebido por http é ignorado pelo navegador; só conta por https.
Há um reverso. Se um navegador tiver memorizado o HSTS e encontrar um erro de certificado (expirado, nome errado), o visitante não recebe nenhum botão para continuar mesmo assim. O seu site fica então inacessível para esses visitantes até o certificado estar correto. Por isso:
- Ative o HSTS apenas quando o https funcionar em todo o lado e a renovação for automática (lição 7.3).
- Comece com um
max-agecurto, por exemplo um dia (86400), e aumente gradualmente até um ano. - Tenha cuidado com
includeSubDomains: aplica-se a todos os subdomínios, incluindo um subdomínio antigo com um equipamento ou serviço sem certificado válido. preloadpede a inclusão numa lista integrada nos navegadores (hstspreload.org). Para isso exigem, entre outros requisitos, ummax-agede pelo menos um ano,includeSubDomainse https em todos os subdomínios. Sair da lista demora meses. Faça-o apenas se tiver a certeza de que todo o domínio fica definitivamente em https.
Os outros cabeçalhos de segurança
Além do HSTS, há alguns cabeçalhos que, com pouco esforço, ajudam muito:
| Cabeçalho | Contra o quê | Valor inicial |
|---|---|---|
X-Content-Type-Options | o navegador tenta adivinhar o tipo de um ficheiro, pelo que uma "imagem" carregada pode ser executada como script | nosniff |
Content-Security-Policy: frame-ancestors (ou o mais antigo X-Frame-Options) | clickjacking: outro site carrega a sua página de forma invisível numa frame | frame-ancestors 'self' (ou X-Frame-Options: SAMEORIGIN) |
Referrer-Policy | o endereço da sua página (com termos de pesquisa ou números de encomenda) é divulgado a outros sites | strict-origin-when-cross-origin |
Um Content-Security-Policy completo (que scripts e estilos podem ser carregados) é feito à medida de cada site e está fora do âmbito deste curso; comece apenas com frame-ancestors.
No Caddy, define-os com a diretiva header no bloco de um site:
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
}
}O Caddy não define o HSTS nem estes cabeçalhos por si só; tem mesmo de os acrescentar. -Server remove o cabeçalho Server. Na lição 9.4, define num bloco do mesmo tipo o seu próprio cabeçalho X-Weboke-Cursus para o exercício.
No nginx, coloca as mesmas regras no bloco server da porta 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 garante que também são enviados com as páginas de erro. Atenção a uma armadilha conhecida do nginx: se um bloco location tiver ele próprio um add_header, as regras add_header do bloco server deixam de se aplicar a essa location. Por isso, verifique sempre o 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-originsecurity.txt: assim alguém lhe pode comunicar uma falha
Imagine que alguém encontra uma falha no seu servidor, como uma pasta aberta ou um serviço desatualizado. Como sabe essa pessoa quem deve avisar? É para isso que serve o security.txt (RFC 9116): um pequeno ficheiro de texto num local fixo, 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.txtAs regras:
Contacté obrigatório: um endereçomailto:,https://outel:para onde vão as comunicações. Utilize um endereço que alguém leia realmente.Expiresé obrigatório e só pode aparecer uma vez: a data a partir da qual o ficheiro é considerado desatualizado. O RFC recomenda uma data no prazo de um ano. Assim, não fica publicado um ficheiro com um endereço há muito esquecido. Anote na sua agenda quando o deve renovar.Preferred-Languages,CanonicalePolicy(uma ligação para a sua política de comunicações) são opcionais.- O ficheiro tem de ser servido por https, como texto simples (
text/plain, UTF-8). O local antigo/security.txtpode existir como extra, mas/.well-known/tem prioridade.
Colocá-lo num site 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-8Se utilizar no nginx a regra de recurso location ~ /\. { deny all; } da lição 7.2, coloque antes dela uma exceção: location ^~ /.well-known/ { }. Para uma aplicação por detrás de um proxy inverso, pode no Caddy fazer o caminho /.well-known/security.txt apontar para um ficheiro com um bloco handle e file_server.
Um erro frequente: um site ou aplicação que responde a qualquer caminho desconhecido com a página inicial e o estado 200. Nesse caso, o security.txt "existe", mas é HTML. Verifique, portanto, também o conteúdo.
No AlmaLinux e no Rocky Linux
Aí, o Caddy vem do repositório dos criadores ou do EPEL/COPR. Tal como no nginx, o SELinux tem de permitir um proxy inverso (setsebool -P httpd_can_network_connect 1). O Caddyfile e os cabeçalhos são iguais.
Resumo
- O Caddy trata sozinho dos certificados, da renovação e do redirecionamento para https;
reverse_proxytransmite automaticamente os cabeçalhos corretos. - O HSTS faz os navegadores memorizarem que o seu site é apenas https; aumente o
max-agegradualmente, tenha cuidado comincludeSubDomainse muito cuidado compreload. - Defina também
X-Content-Type-Options: nosniff,frame-ancestors 'self'e umReferrer-Policy; no Caddy comheader, no nginx comadd_header ... always, e verifique comcurl -I. - O security.txt fica em
/.well-known/security.txt, por https, como texto simples, comContactobrigatório e um únicoExpiresno prazo de um ano.
Questionário
Exercício
Exercício Z7.4: HSTS, cabeçalhos e security.txt. Defina para o seu site o HSTS (pelo menos 180 dias, depois de o https funcionar bem durante algum tempo), X-Content-Type-Options: nosniff e frame-ancestors 'self' (ou X-Frame-Options), e publique um security.txt com Contact e um Expires no prazo de um ano. Introduza o nome do seu servidor. O programa obtém https://<hostnaam>/ e verifica os cabeçalhos, e obtém https://<hostnaam>/.well-known/security.txt e verifica os campos. Não guarda nada além do resultado e da data de Expires.
Para saber mais
- HSTS e cabeçalhos de segurança para o seu website
- Caddy, Automatic HTTPS: https://caddyserver.com/docs/automatic-https
- Caddy, diretiva header: https://caddyserver.com/docs/caddyfile/directives/header
- RFC 6797, HTTP Strict Transport Security: https://www.rfc-editor.org/rfc/rfc6797.html
- Lista de preload HSTS e os requisitos: https://hstspreload.org/
- RFC 9116, security.txt: https://www.rfc-editor.org/rfc/rfc9116.html
- securitytxt.org (criar e verificar): https://securitytxt.org/
- Colocar um security.txt no seu website
- VPS: do primeiro início de sessão a um servidor seguro 5.1: Caddy: um site com https automático
