Własna strona na nazwie .lopux
Masz nazwę w Lopux-Internecie; ta instrukcja stawia za nią prawdziwą stronę, dostępną dla każdego, kto używa aplikacji. Jeśli nazwy jeszcze nie masz — najpierw ją zajmij.
Zakłada, że potrafisz uruchomić serwer WWW i nic ponadto. Wszystko, co jest specyficzne dla Lopux-Internetu, jest tutaj: dlaczego certyfikat jest samopodpisany, co musi działać obok Twojej strony i które dwa rekordy sprawiają, że nazwa działa.
Zrzuty ekranu pokazują angielski interfejs. Portal mówi w sześciu językach — wybierz swój przyciskiem EN w prawym górnym rogu.
1. Czego potrzebujesz i co się nie nada
Maszyna, na której to Ty panujesz nad TLS na porcie 443. VPS, serwer dedykowany, komputer w domu z osiągalnym adresem. To całe wymaganie i jest ono prawdziwe.
Platformy zarządzane tego nie udźwigną, z dwóch niezależnych powodów. Vercel, Netlify, Cloudflare Pages, większość PaaS: dodajesz własną domenę, a certyfikat zdobywają i podają oni. Cała rzecz polega tu na tym, że Twój serwer dowodzi posiadania klucza, który opublikowałeś Ty — platforma podająca własny klucz takiego dowodu nie przeprowadzi, a aplikacja odwiedzającego odrzuci stronę i będzie miała rację. Nazwy zresztą i tak nie przyjmą: konfiguracja własnej domeny weryfikuje własność przez zwykły DNS, w którym mysite.lopux nie istnieje i istnieć nie będzie.
CDN z przodu też nie pomaga — kończy TLS u siebie, czyli ten sam problem.
Platformy pozwalające wgrać własny certyfikat razem z kluczem zadziałałyby mechanicznie, ale wtedy ta strona może podszywać się pod Twoją witrynę przed każdym odwiedzającym, po cichu, i nic w tej konstrukcji tego nie wykryje. Potraktuj to jak to, czym jest: oddanie komuś swojego klucza prywatnego.
2. Dlaczego certyfikat jest samopodpisany
Żaden urząd certyfikacji nie może wystawić certyfikatu na nazwę w Lopux-Internecie. Nie dlatego, że to trudne, tylko dlatego, że nie wolno: urząd może wystawiać wyłącznie na nazwy pod zwykłym korzeniem DNS, a te nazwy leżą celowo poza nim.
Zamiast prosić obcego o poręczenie, publikujesz odcisk własnego klucza w strefie swojej nazwy, a aplikacja każdego odwiedzającego porównuje serwer, do którego dotarła, z tym rekordem. To rekord jest tu instancją rozstrzygającą.
Pod jednym względem jest to ostrzejsze niż urząd certyfikacji: przy urzędzie certyfikat na Twoją nazwę mogłyby wystawić setki organizacji i każdej by uwierzono. Tutaj działa wyłącznie klucz, który opublikowałeś Ty.
3. Zrób certyfikat
Dziesięć lat, bez hasła, i każda nazwa, którą obsługujesz, wymieniona w subjectAltName:
openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 \
-keyout site.key -out site.crt -days 3650 -nodes \
-subj "/CN=mysite.lopux" \
-addext "subjectAltName=DNS:mysite.lopux,DNS:www.mysite.lopux"
Trzy rzeczy o tym poleceniu:
- daty ważności nie mają tu znaczenia. Aplikacje ignorują je celowo: o tym, czy Twój klucz nadal jest dobry, decyduje opublikowany rekord, a nie data w certyfikacie. Nie ma więc żadnego
odnawiania, nigdy. Dziesięć lat to po prostu dłużej, niż będzie Cię to obchodzić;
-nodesznaczy, że klucz nie ma hasła, a właśnie tego potrzebuje serwer WWW, żeby wstać bez człowieka. Trzymaj plik czytelny tylko dla użytkownika serwera (chmod 600) i poza obrazami,
które gdziekolwiek wypychasz;
- nie wkładaj do certyfikatu niczego, czego byś nie opublikował. Każdy, kto dokończy uzgadnianie
z Twoim serwerem, dostaje go i odczytuje z niego nazwę. Jedna nazwa, bez organizacji i adresu e-mail.
4. Co działa obok Twojej strony
Twoja strona mówi zwykłym HTTP i nigdy nie widzi certyfikatu. Przed nią stoi nginx, który kończy TLS opublikowanym kluczem i przekazuje żądanie do środka.
Ten front istnieje, bo źródło w Lopux-Internecie potrzebuje kilku ustawień odwrotnych do tego, co daje zwykły „utwardzony nginx", a każde z nich psuje się w sposób, który w przeglądarce wygląda dobrze:
| Zasada | Co kosztuje pomyłka |
|---|---|
| żadnego HSTS — i zdejmij go, jeśli strona wysyła własny | nagłówek przypina przeglądarkę do https:// dla tej nazwy, co trwale psuje tryb zwykłego http://, który odwiedzający ma, zanim cokolwiek zainstaluje |
żadnego przekierowania na https:// — i powiedz stronie, że żądanie już przyszło po TLS | inaczej framework wystawi to przekierowanie sam i zepsuje ten sam tryb od środka |
| odrzucaj uzgadnianie, w którym SNI to nie Twoja nazwa | skaner przechodzący po adresach zbierze Twój certyfikat, a w certyfikacie jest Twoja nazwa |
| tylko 443 | aplikacje pukają w 443 i nigdzie indziej; port 80 nie obsługuje nikogo, kto przyszedł przez Lopux-Internet |
| terminy na uzgadnianie i na odczyt | jedno połączenie, które się otwiera i milczy, potrafi zablokować serwer. Publiczny adres zbiera takie w ciągu minut |
| front trzyma klucz, a skok do środka idzie zwykłym HTTP | ten skok nie może więc opuszczać maszyny: nie publikuj na zewnątrz portu samej strony |
Oto ten nginx w całości. Podmień nazwę, ścieżki i adres zaplecza:
map $http_upgrade $connection_upgrade { default upgrade; '' close; }
server_tokens off;
# nie Twoja nazwa: zamknięte drzwi, przed certyfikatem
server {
listen 443 ssl default_server;
listen [::]:443 ssl default_server;
ssl_reject_handshake on;
}
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
server_name mysite.lopux;
ssl_certificate /etc/ssl/site.crt; # klucz, którego odcisk publikujesz
ssl_certificate_key /etc/ssl/site.key;
ssl_protocols TLSv1.2 TLSv1.3; # samopodpisany: nie ma czego zszywać
client_header_timeout 10s; # ograniczają uzgadnianie — patrz niżej
client_body_timeout 10s;
send_timeout 10s;
keepalive_timeout 30s;
reset_timedout_connection on;
proxy_hide_header Strict-Transport-Security;
location / {
proxy_pass http://127.0.0.1:8080; # Twoja strona, HTTP, nie na zewnątrz
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto https; # zasada 2: bez przekierowania
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_connect_timeout 5s;
proxy_read_timeout 60s;
}
}
Jedna pułapka w tych terminach, przez którą nginx po prostu nie wstanie: ssl_handshake_timeout nie istnieje w module http nginx — należy do stream. W http uzgadnianie ogranicza client_header_timeout i to właśnie ta wartość wykonuje tu tę pracę.
O bramce SNI warto powiedzieć osobno, bo robi coś mniej oczywistego niż chowanie się przed skanerami. Bez niej serwer podaje ten sam certyfikat — a więc to samo ostrzeżenie przeglądarki — dwóm odwiedzającym w przeciwstawnych sytuacjach: temu, którego aplikacja porównała Twój klucz z rekordem, zanim ruszył choć jeden bajt strony, i temu, kto wpisał Twój adres IP, gdzie nie sprawdzono niczego. Bramka usuwa ten drugi przypadek. Nie zamienia ostrzeżenia w weryfikację: kto zna Twoją nazwę, wpisze ją sobie do własnego hosts i przyjdzie niesprawdzony dokładnie jak wcześniej.
Jedna zasada dotycząca samych stron, łatwo ją przeoczyć: używaj odnośników względnych. /about, a nie https://mysite.lopux/about. Odwiedzający w trybie zwykłego http:// nie przejdzie po bezwzględnym odnośniku https:// do Twojej własnej strony, a Lopux-Internet celowo nie przepisuje Twoich stron. Odnośniki do innych witryn to Twoja sprawa i nic im nie jest.
5. Opublikuj odcisk klucza
Otwórz swoją nazwę w portalu i przewiń do sekcji Certyfikaty. Dopóki nic nie jest opublikowane, mówi to wprost: nie ma z czym porównać, więc aplikacja odmówi otwarcia strony, zamiast łączyć się bez weryfikacji.
Wgraj site.crt przyciskiem Wybierz plik certyfikatu… albo wklej go. Tylko certyfikat — plik zaczynający się od -----BEGIN PRIVATE KEY----- zostaje na Twoim serwerze, a portal go odrzuci, zamiast gdzieś zapisać.
Naciśnij Opublikuj odcisk klucza. Portal odczyta certyfikat, weźmie SHA-256 jego klucza publicznego i zapisze wynik w Twojej strefie.
Porównaj go z własną kopią — muszą się zgadzać:
openssl x509 -in site.crt -noout -pubkey \
| openssl pkey -pubin -outform der | openssl dgst -sha256
Ta sekcja to frontowe drzwi do zwykłego rekordu. Ta sama wartość leży na liście rekordów jako rekord TLSA pod _443._tcp i tam ją widać:
6. Skieruj nazwę na swój serwer
W tym samym widoku dodaj rekord A, którego wartością jest publiczny adres Twojego serwera. @ oznacza samą nazwę.
Teraz strefa niesie oba rekordy i razem są one wszystkim, czego potrzebuje aplikacja odwiedzającego: rekord A mówi, gdzie jest Twój serwer, a TLSA — jaki klucz musi on okazać.
Załóż jakieś dziesięć minut, zanim zmiana będzie widoczna wszędzie. Po drodze stoją dwie pamięci podręczne — resolwera i aplikacji — po pięć minut każda.
7. Sprawdź
Portal pobiera Twoją stronę tak, jak zrobiłby to odwiedzający, i mówi, co przeszkodziłoby jej działać: klucz niezgodny z opublikowanym, brakujący odcisk, nagłówek HSTS, przekierowanie na https://, bezwzględne odnośniki do siebie albo serwer, który nie odpowiedział.
Na tym zrzucie sprawdzenie odmawia wykonania: adres w przykładzie jest adresem dokumentacyjnym, a portal nie zagląda tam, gdzie nie da się dotrzeć z internetu — skierowanie nazwy na adres prywatny lub pętli zwrotnej zamieniłoby sprawdzenie w sondowanie czyjejś sieci. Przy prawdziwym serwerze pod prawdziwym adresem odpowiada, że ze stroną wszystko w porządku, albo nazywa dokładnie, co jest nie tak.
Dwa sprawdzenia, które możesz zrobić sam, i to właśnie one liczą się najbardziej:
# bez SNI — odmowa
openssl s_client -connect YOUR_ADDRESS:443 </dev/null
# Twój certyfikat
openssl s_client -connect YOUR_ADDRESS:443 -servername mysite.lopux </dev/null
Drugie powinno podać Ci certyfikat, którego odcisk opublikowałeś. Weź odcisk jego klucza tak samo jak w §5 i porównaj: jeśli ciągi się różnią, każdy odwiedzający dostaje odmowę, a dla niego wygląda to dokładnie jak próba podszycia się.
8. Co widzi odwiedzający
Dobrze ustawiona strona otwiera się pod własną nazwą, jak każda inna:
To lopux.ipvx — własna strona tego projektu. Żyje w przestrzeni nazw tak samo, jak będzie żyła Twoja, i jest postawiona dokładnie w tym kształcie. Klucz, który podaje, zgadza się z jej opublikowanym odciskiem — i właśnie dlatego aplikacja otwiera ją bez słowa ostrzeżenia.
Co dostają różni odwiedzający:
| Odwiedzający | Co widzi |
|---|---|
aplikacja, nazwa w otwartej strefie takiej jak .lopux | zwykła kłódka, wszystko działa |
| aplikacja, własna nazwa korzeniowa | za każdym razem ostrzeżenie przeglądarki o certyfikacie — odcisk i tak jest sprawdzany pod spodem |
aplikacja, http:// w pasku adresu | strona wygląda skromnie; skok do Twojego serwera i tak jest szyfrowany, a klucz sprawdzony |
| bez aplikacji | nic. Nazwa nie rozwiązuje się poza Lopux-Internetem |
Ostatni wiersz to sens przestrzeni nazw, a nie jej ograniczenie. Zwróć jednak uwagę na wiersz wyżej: Twój serwer to zwykła publiczna maszyna i każdy może do niego trafić po adresie. Przestrzeń nazw go nie ukrywa, a Twój certyfikat podaje nazwę Twojej strony każdemu, kto dokończy uzgadnianie — po to właśnie jest bramka SNI z §4.
9. Jak dbać o klucz
Nic tutaj nie wykryje kradzieży klucza; system czyni jedynie wiążącym powiązanie Twojej nazwy z Twoim kluczem. Ten, kto ma Twój klucz, uwierzytelnia się bez zarzutu, dopóki nie opublikujesz nowego odcisku.
- trzymaj
site.keyczytelny tylko dla użytkownika serwera WWW i poza katalogiem, który serwujesz; - zrób zaszyfrowaną kopię zapasową: utrata klucza kosztuje Cię wymianę, a nie nazwę;
- wymiana jest tania, więc rób ją przy każdym podejrzeniu. Opublikuj nowy certyfikat przed przełączeniem: przy dwóch opublikowanych odciskach akceptowany jest każdy z kluczy, więc nie ma chwili, w której strona byłaby nieosiągalna. Potem przełącz serwer, odczekaj dziesięć minut i usuń stary;
- usunięcie odcisku jest unieważnieniem. Nie ma kogo pytać ani na co czekać: w oknie pamięci podręcznej odwiedzający dostaje odmowę, zamiast zobaczyć tego, kto ma stary klucz.
10. Kiedy coś jest nie tak
Aplikacja nazywa usterkę, zamiast pokazywać pustą stronę. Co znaczy każda z nich:
| Co słyszy odwiedzający | Co to znaczy | Czyj ruch |
|---|---|---|
| Dla tej nazwy nie opublikowano odcisku klucza | w strefie nie ma rekordu TLSA | Twój — §5 |
| To nie jest strona, za którą się podaje | klucz Twojego serwera nie jest tym opublikowanym | Twój — zmieniłeś certyfikat, nie publikując nowego odcisku |
| Strona nie odpowiedziała | nazwa i klucz są w porządku, serwer się nie odezwał | Twój — sprawdź serwer i rekord A |
| Ta strona nie może działać po zwykłym http | bezwzględne odnośniki https:// do Twojej własnej strony | Twój — zrób je względnymi (§4) |
| Ta aplikacja potrzebuje aktualizacji, żeby otworzyć tę stronę | aplikacja odwiedzającego jest starsza niż Twoja strefa | jego — niech zaktualizuje; z Twoją stroną wszystko dobrze |