Caddy, HSTS i security.txt
Moduł 7: Domena, serwer WWW i https · Czas czytania: 12 min
Cel lekcji: Po tej lekcji będą Państwo potrafili używać Caddy jako prostego serwera WWW z automatycznym https, ustawić HSTS i najważniejsze nagłówki bezpieczeństwa (w Caddy i nginx) bez ryzyka, że strona stanie się nieosiągalna, oraz opublikować poprawny plik security.txt.
Kluczowe pojęcia: Caddy, Caddyfile, automatyczne https, 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 bez zachodu
W lekcjach 7.2 i 7.3 zbudowali Państwo stronę z https za pomocą nginx i certbota. To dwa programy, kilka plików i timer. Caddy robi to wszystko w jednym: jest serwerem WWW z wbudowanym klientem ACME. Jeśli nazwa znajduje się w konfiguracji, wskazuje na serwer, a porty 80 i 443 są osiągalne, Caddy sam pobiera certyfikat, odnawia go na czas i przekierowuje http na https.
Caddy jest dostępny w repozytorium pakietów Debiana i Ubuntu (w nieco starszej wersji); twórcy oferują także własne źródło apt z najnowszą wersją, z własnym kluczem i Signed-By, tak jak w lekcji 4.1. W module 9 Caddy działa jako kontener dla Państwa usług Docker (lekcja 9.4). Tutaj używamy go jako zwykłej usługi.
anna@web1:~$ sudo apt install caddy
anna@web1:~$ systemctl status caddyNa portach 80 i 443 prosimy używać albo nginx, albo Caddy, nie obu jednocześnie: na danym porcie może nasłuchiwać tylko jeden program.
Plik Caddyfile
Konfiguracja znajduje się w /etc/caddy/Caddyfile. Strona statyczna i aplikacja za reverse proxy:
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
}To wszystko. Caddy sam nasłuchuje na IPv4 i IPv6, wnioskuje o certyfikaty dla trzech nazw, przekierowuje http na https, a przy reverse_proxy automatycznie przekazuje nagłówki X-Forwarded-For i X-Forwarded-Proto (w nginx robili to Państwo ręcznie, lekcja 7.2).
Testowanie i przeładowanie działa tak jak w nginx:
anna@web1:~$ caddy validate --config /etc/caddy/Caddyfile
Valid configuration
anna@web1:~$ sudo systemctl reload caddy
anna@web1:~$ sudo journalctl -u caddy -fW journalu widać pobieranie certyfikatów. Jeśli coś pójdzie nie tak, znajdą tam Państwo przyczynę: zwykle tę samą co przy certbocie (zamknięty port 80, nazwa wskazuje gdzie indziej, niedziałające IPv6; lekcja 7.3).
HSTS: przeglądarka zapamiętuje, że to https
Przekierowanie z http na https ma jeden słaby moment: pierwsze żądanie przez http nadal idzie bez szyfrowania. Ktoś w tej samej sieci może je przechwycić i zatrzymać odwiedzającego na http. HSTS (HTTP Strict Transport Security, RFC 6797) rozwiązuje ten problem. Państwa strona wysyła przez https taki nagłówek:
Strict-Transport-Security: max-age=31536000Przeglądarka zapamiętuje wtedy na rok (31.536.000 sekund), że ta nazwa jest dostępna wyłącznie przez https. Gdy odwiedzający wpisze później http://, przeglądarka sama zamieni to na https, zanim cokolwiek trafi do sieci. Nagłówek HSTS otrzymany przez http przeglądarka ignoruje; liczy się tylko przez https.
Jest też druga strona medalu. Jeśli przeglądarka zapamiętała HSTS i napotka błąd certyfikatu (wygasły, niewłaściwa nazwa), odwiedzający nie otrzyma przycisku, aby mimo to kontynuować. Strona jest wtedy dla tych osób nieosiągalna, dopóki certyfikat nie będzie poprawny. Dlatego:
- Prosimy włączyć HSTS dopiero wtedy, gdy https działa wszędzie, a odnawianie odbywa się automatycznie (lekcja 7.3).
- Prosimy zacząć od krótkiego
max-age, na przykład jednego dnia (86400), i stopniowo zwiększać go do roku. - Prosimy uważać na
includeSubDomains: dotyczy to każdej subdomeny, także starej subdomeny z urządzeniem lub usługą bez ważnego certyfikatu. preloadto prośba o wpisanie na listę wbudowaną w przeglądarki (hstspreload.org). Wymagane są m.in.max-agewynoszący co najmniej rok,includeSubDomainsoraz https na wszystkich subdomenach. Usunięcie z listy trwa miesiącami. Prosimy robić to tylko wtedy, gdy mają Państwo pewność, że cała domena na zawsze pozostanie na https.
Pozostałe nagłówki bezpieczeństwa
Oprócz HSTS istnieje kilka nagłówków, które niewielkim nakładem pracy dużo pomagają:
| Nagłówek | Przed czym chroni | Wartość na początek |
|---|---|---|
X-Content-Type-Options | przeglądarka zgaduje, czym jest plik, przez co przesłany "obrazek" może zostać uruchomiony jako skrypt | nosniff |
Content-Security-Policy: frame-ancestors (lub starszy X-Frame-Options) | clickjacking: inna strona niewidocznie ładuje Państwa stronę w ramce | frame-ancestors 'self' (lub X-Frame-Options: SAMEORIGIN) |
Referrer-Policy | adres Państwa strony (z wyszukiwanymi frazami lub numerami zamówień) wycieka do innych stron | strict-origin-when-cross-origin |
Pełna polityka Content-Security-Policy (które skrypty i style mogą się ładować) to rozwiązanie szyte na miarę każdej strony i wykracza poza ten kurs; prosimy zacząć tylko od frame-ancestors.
W Caddy ustawia się je dyrektywą header w bloku danej strony:
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 nie ustawia HSTS ani tych nagłówków samodzielnie; trzeba je więc naprawdę dodać. -Server usuwa nagłówek Server. W lekcji 9.4 w takim samym bloku ustawią Państwo własny nagłówek X-Weboke-Cursus na potrzeby zadania.
W nginx te same reguły umieszcza się w bloku server dla portu 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 sprawia, że są wysyłane również przy stronach błędów. Prosimy uważać na znaną pułapkę nginx: jeśli w samym bloku location znajduje się choć jedno add_header, reguły add_header z bloku server przestają obowiązywać dla tej lokalizacji. Dlatego zawsze prosimy sprawdzić wynik:
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: tak można zgłosić Państwu lukę
Załóżmy, że ktoś znajdzie lukę na Państwa serwerze, na przykład otwarty katalog lub przestarzałą usługę. Skąd ta osoba ma wiedzieć, kogo ostrzec? Do tego służy security.txt (RFC 9116): mały plik tekstowy w stałym miejscu, 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.txtZasady:
Contactjest obowiązkowe: adresmailto:,https://lubtel:, na który trafiają zgłoszenia. Prosimy użyć adresu, który ktoś naprawdę czyta.Expiresjest obowiązkowe i może wystąpić tylko raz: data, po której plik uznaje się za nieaktualny. RFC zaleca datę w ciągu roku. Dzięki temu nie zostaje plik z dawno zapomnianym adresem. Prosimy zapisać w kalendarzu, kiedy trzeba go przedłużyć.Preferred-Languages,CanonicaliPolicy(link do Państwa zasad przyjmowania zgłoszeń) są opcjonalne.- Plik musi być dostępny przez https, jako zwykły tekst (
text/plain, UTF-8). Stara lokalizacja/security.txtmoże istnieć dodatkowo, ale pierwszeństwo ma/.well-known/.
Umieszczenie pliku w przypadku strony statycznej:
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-8Jeśli w nginx używają Państwo zabezpieczenia location ~ /\. { deny all; } z lekcji 7.2, prosimy dodać przed nim wyjątek: location ^~ /.well-known/ { }. W przypadku aplikacji za reverse proxy można w Caddy skierować ścieżkę /.well-known/security.txt do pliku za pomocą bloku handle i file_server.
Częsty błąd: strona lub aplikacja odpowiada na każdą nieznaną ścieżkę stroną główną ze statusem 200. Wtedy security.txt "istnieje", ale jest to HTML. Prosimy więc sprawdzić także zawartość.
W AlmaLinux i Rocky Linux
Caddy pochodzi tam ze źródła twórców albo z EPEL/COPR. Podobnie jak w przypadku nginx, SELinux musi zezwolić na reverse proxy (setsebool -P httpd_can_network_connect 1). Caddyfile i nagłówki są takie same.
Podsumowanie
- Caddy sam obsługuje certyfikaty, odnawianie i przekierowanie na https;
reverse_proxyautomatycznie przekazuje właściwe nagłówki. - HSTS sprawia, że przeglądarki zapamiętują, iż Państwa strona działa tylko przez https; prosimy stopniowo zwiększać
max-age, uważać naincludeSubDomainsi bardzo uważać napreload. - Prosimy ustawić także
X-Content-Type-Options: nosniff,frame-ancestors 'self'iReferrer-Policy; w Caddy za pomocąheader, w nginx za pomocąadd_header ... always, i sprawdzić wynik za pomocącurl -I. - security.txt znajduje się pod
/.well-known/security.txt, jest dostępny przez https, jako zwykły tekst, z obowiązkowymContacti jednymExpiresw ciągu roku.
Quiz
Zadanie
Zadanie Z7.4: HSTS, nagłówki i security.txt. Prosimy ustawić dla swojej strony HSTS (co najmniej 180 dni, gdy https już przez jakiś czas działa poprawnie), X-Content-Type-Options: nosniff oraz frame-ancestors 'self' (lub X-Frame-Options) i opublikować plik security.txt z Contact oraz Expires w ciągu roku. Prosimy wpisać nazwę hosta. Program pobiera https://<hostnaam>/ i sprawdza nagłówki, a następnie pobiera https://<hostnaam>/.well-known/security.txt i sprawdza pola. Nie zapisuje niczego poza wynikiem i datą Expires.
Przeczytaj więcej
- Nagłówki HSTS i nagłówki bezpieczeństwa dla Państwa strony internetowej
- Caddy, Automatic HTTPS: https://caddyserver.com/docs/automatic-https
- Caddy, dyrektywa header: https://caddyserver.com/docs/caddyfile/directives/header
- RFC 6797, HTTP Strict Transport Security: https://www.rfc-editor.org/rfc/rfc6797.html
- Lista HSTS preload i wymagania: https://hstspreload.org/
- RFC 9116, security.txt: https://www.rfc-editor.org/rfc/rfc9116.html
- securitytxt.org (tworzenie i sprawdzanie): https://securitytxt.org/
