UFW i IPv6: jak zabezpieczyć otwarte porty na VPS
Wiele usług na VPS nasłuchuje na IPv6 mimo skonfigurowanego UFW dla IPv4. Sprawdź, dlaczego Twoje reguły mogą być nieskuteczne i jak poprawnie zablokować dostęp w Ubuntu.
Pułapka firewalla IPv6 w jednym zdaniu
Twój firewall chroni protokół IPv4. Twój VPS niemal na pewno posiada również publiczny adres IPv6, a wiele usług nasłuchuje na nim domyślnie. Jeśli Twój firewall obsługuje tylko IPv4 lub polegasz na chmurowym firewallu filtrującym wyłącznie ruch IPv4, każda z tych usług jest dostępna z całego Internetu przez IPv6, podczas gdy strona IPv4 wydaje się zabezpieczona. Testujesz port za pomocą curl, widzisz odmowę połączenia i czujesz się bezpiecznie. Atakujący łączy się z tym samym portem przez IPv6 i uzyskuje dostęp.
Ten przewodnik pokazuje, skąd bierze się ta luka w standardowym systemie Ubuntu 24.04 VPS, jak dokładnie sprawdzić, co jest wystawione na zewnątrz, oraz jak to zabezpieczyć. UFW nie jest tutaj winowajcą. W nowoczesnej instalacji Ubuntu narzędzie UFW obsługuje już IPv6. Ekspozycja wynika z warstw otaczających firewall oraz z usług, o których nasłuchiwaniu nie wiesz.
Dlaczego Twój VPS domyślnie korzysta z IPv6
Prawie każdy współczesny VPS jest dostarczany z publicznym adresem IPv6, często z całą podsiecią /64, obok adresu IPv4. Sprawdź swój adres:
ip -6 addr show scope global2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> ...
inet6 2001:db8:2a::1/64 scope globalTen 2001:db8:2a::1 jest osiągalny z dowolnego miejsca w Internecie, dokładnie tak samo jak adres IPv4. Teraz sprawdź, co nasłuchuje na portach:
sudo ss -tlnpState Recv-Q Local Address:Port Process
LISTEN 0 0.0.0.0:22 sshd
LISTEN 0 [::]:22 sshd
LISTEN 0 127.0.0.1:5432 postgres
LISTEN 0 [::]:8080 docker-proxyPrzyjrzyj się uważnie kolumnie Local Address. 0.0.0.0:22 oznacza „nasłuchuj na każdym adresie IPv4”. [::]:22 oznacza „nasłuchuj na każdym adresie IPv6”. 127.0.0.1:5432 jest powiązane z interfejsem zwrotnym (loopback) i nie jest publicznie dostępne, więc wpis Postgres jest bezpieczny. Dwie linie [::] odpowiadają całemu Internetowi przez IPv6, a linia docker-proxy to usługa, o której uruchomieniu prawdopodobnie zapomniałeś.
Większość demonów domyślnie wiąże się z ::, ponieważ w systemie Linux gniazdo :: zazwyczaj akceptuje również połączenia IPv4. Zatem domyślny stan świeżego serwera to „odpowiadaj na obu stosach, wszędzie”. Zapora sieciowa jest jedyną barierą chroniącą przed tym stanem, dlatego firewall obsługujący tylko jeden stos protokołów stanowi poważny problem.
Skąd faktycznie bierze się luka w obsłudze IPv6
Istnieją cztery typowe źródła tego problemu. Na danym serwerze może występować jedno z nich lub kilka jednocześnie.
1. Chmurowy firewall filtrujący tylko IPv4. Wiele firewalli dostawców i produktów typu security-group powstało w oparciu o IPv4. Często ignorują one IPv6 lub wymagają ręcznego dodania osobnych reguł dla tego protokołu. Jeśli jedynym firewallem jest ten w panelu dostawcy i nie obejmuje on IPv6, Twoje usługi [::] są otwarte, niezależnie od ustawień dla portu 22 w IPv4. Przeczytaj dokumentację firewalla swojego dostawcy i wyszukaj informacje dotyczące konkretnie IPv6.
2. Ręcznie tworzone reguły iptables bez ip6tables. Polecenie iptables modyfikuje wyłącznie tablice IPv4. IPv6 posiada całkowicie oddzielne polecenie, ip6tables, z własnym zestawem reguł. Jeśli skrypt firewalla zawiera wiele linii iptables -A INPUT ..., a nie posiada odpowiadających im reguł ip6tables, firewall IPv6 pozostaje pusty. Pusty łańcuch INPUT z domyślną polityką ACCEPT przepuszcza cały ruch:
sudo ip6tables -L INPUT -nChain INPUT (policy ACCEPT)
target prot opt source destinationTen wynik to pułapka w pigułce. IPv4 jest filtrowane, a IPv6 akceptuje wszystko z zewnątrz.
3. Docker publikujący porty z pominięciem firewalla. Podczas uruchamiania docker run -p 8080:80, Docker wstawia własne reguły przed reguły UFW. Dzięki temu opublikowany port jest dostępny, nawet jeśli ufw status wskazuje, że port jest zablokowany. W nowszych wersjach Dockera dotyczy to również IPv6. Dlaczego Docker omija UFW i jak poprawnie filtrować porty kontenerów wyjaśnia ten mechanizm oraz sposoby naprawy. Zobacz podstawy Docker Compose na VPS, aby dowiedzieć się, jak deklarowane są te opublikowane porty.
4. UFW z wyłączoną obsługą IPv6. UFW obsługuje IPv6, ale tylko wtedy, gdy zostanie to jawnie skonfigurowane. Sprawdź ustawienie:
grep IPV6 /etc/default/ufwWspółczesne systemy Ubuntu mają ustawione IPV6=yes, dzięki czemu UFW stosuje każdą regułę do obu stosów. Jeśli widzisz IPV6=no (co może wynikać ze starego obrazu systemu lub przestarzałego poradnika), każda utworzona reguła UFW dotyczy tylko IPv4, a IPv6 pozostaje niezarządzane.
Weryfikacja wystawionych usług
Nie należy zgadywać. Należy dokonać pomiaru z zewnątrz. Najpierw należy wyświetlić listę procesów nasłuchujących i zanotować każdy z nich powiązany z :::
sudo ss -tlnp | grep '::'Następnie, z innej maszyny, należy połączyć się z publicznym adresem IPv6 serwera i sprawdzić port, który powinien być zamknięty:
curl -6 -v http://[2001:db8:2a::1]:8080/Jeśli zwrócona zostanie strona lub baner, port jest otwarty w protokole IPv6. Zamknięty port zwraca Connection refused lub przekroczenie czasu oczekiwania. Te dwa błędy nie oznaczają tego samego, a różnica między połączeniem odrzuconym a przekroczeniem czasu informuje, czy host odpowiedział i odmówił dostępu, czy też firewall odrzucił pakiet w sposób niezauważalny. Aby uzyskać pełny obraz, należy przeskanować adres IPv6 za pomocą nmap z maszyny zewnętrznej:
nmap -6 2001:db8:2a::1Każdy port, który nmap wskazuje jako otwarty w IPv6, jest portem dostępnym z całego Internetu, niezależnie od wyników skanowania IPv4. Porównanie skanów IPv4 oraz IPv6 obok siebie to najszybszy sposób na wykrycie luki: każda usługa otwarta na -6, a zamknięta na IPv4, jest usługą, której firewall nie zabezpiecza.
Zamknięcie luki
Skonfiguruj UFW dla obu stosów i ustaw domyślną politykę odmowy. Potwierdź przełączenie, ustaw domyślną politykę odmowy dla ruchu przychodzącego i zezwól tylko na niezbędny ruch:
sudo sed -i 's/^IPV6=no/IPV6=yes/' /etc/default/ufw
sudo ufw default deny incoming
sudo ufw allow 22/tcp
sudo ufw enable
sudo ufw status verboseJeśli UFW był aktywny w momencie zmiany IPV6=yes, zmiana nie wejdzie w życie do czasu wykonania sudo ufw reload.
ufw status wyświetla każdą regułę dwukrotnie: raz w wersji podstawowej, a raz z przyrostkiem (v6). Obecność linii (v6) oznacza, że UFW filtruje ruch IPv6:
22/tcp ALLOW IN Anywhere
22/tcp (v6) ALLOW IN Anywhere (v6)Jeśli zarządzasz iptables ręcznie, odzwierciedlaj każdą regułę w ip6tables lub przejdź na nftables, którego tablice inet obsługują IPv4 i IPv6 w jednym miejscu, eliminując ten rodzaj błędów. Pojedyncza tablica filtrów inet w nftables jest najczystszym rozwiązaniem przy samodzielnym tworzeniu reguł. Jeśli Twój VPS korzysta z Rocky lub AlmaLinux zamiast Ubuntu, nie ma tam UFW do skonfigurowania, a firewalld jest interfejsem, którym zarządzasz, który stosuje reguły strefowe do obu stosów jednocześnie.
Powiąż usługi, które nie powinny być publiczne, z interfejsem loopback. Baza danych, panel administracyjny czy punkt końcowy metryk rzadko wymagają publicznego adresu. Powiąż je z 127.0.0.1 oraz ::1, aby usługa w ogóle nie nasłuchiwała na adresie routowalnym. W przypadku Postgres ustaw listen_addresses = 'localhost'. W przypadku serwera aplikacji powiąż go z 127.0.0.1 i umieść przed nim reverse proxy. Zamknięcie portu nasłuchującego jest skuteczniejsze niż jego blokowanie firewallem, ponieważ w ten sposób usługa staje się nieosiągalna.
Nie ufaj UFW w kwestii ochrony portów udostępnionych przez Docker. Publikuj porty kontenerów na konkretnym adresie zamiast na wszystkich interfejsach, na przykład -p 127.0.0.1:8080:80, aby port był dostępny tylko z poziomu hosta oraz usług, które celowo przekierowujesz przez proxy. Gdy kontener musi być publicznie dostępny, umieść go za reverse proxy Traefik i publikuj tylko proxy, a nie każdą aplikację z osobna.
Dodaj reguły IPv6 do firewalla dostawcy lub zaakceptuj fakt, że nie jest on Twoim firewallem dla IPv6 i pozwól, aby to zadanie przejął UFW lub nftables na hoście.
Weryfikacja zamknięcia portów
Po wprowadzeniu zmian ponownie wykonaj test zewnętrzny:
curl -6 -v http://[2001:db8:2a::1]:8080/
nmap -6 2001:db8:2a::1Port, który wcześniej odpowiadał, powinien teraz odrzucić połączenie lub przekroczyć czas oczekiwania, a nmap powinien zgłosić stan filtered lub closed. Jeśli port nadal pozostaje otwarty, przeanalizuj ponownie cztery powyższe źródła: usługę wciąż powiązaną z :: bez reguły blokującej, regułę Docker znajdującą się przed UFW lub zaporę sieciową dostawcy, która w ogóle nie uwzględnia IPv6.
Całkowite odizolowanie wrażliwych usług od publicznego Internetu jest jeszcze skuteczniejszym rozwiązaniem. Umieść SSH oraz panele administracyjne za VPN WireGuard i skonfiguruj zaporę tak, aby porty odpowiadały tylko wewnątrz tunelu; problem ekspozycji IPv6 przestanie ich dotyczyć. Aby spowolnić skanowanie typu brute-force wymierzone w usługi publiczne, zastosuj Fail2ban przed SSH jako dodatkową warstwę ochrony przy domyślnej polityce zaporowej typu deny.
Jeśli pojęcie portów jest nowe, czym są porty i jak usługi nasłuchują to podstawowy materiał, od którego należy zacząć.
FAQ
Czy UFW domyślnie blokuje IPv6?
W nowoczesnej instalacji Ubuntu 24.04 – tak. UFW odczytuje IPV6=yes z /etc/default/ufw i stosuje każdą regułę zarówno do IPv4, jak i IPv6, a ufw status wyświetla reguły IPv6 z przyrostkiem (v6). Pułapka pojawia się przy IPV6=no (wynikającej ze starego obrazu systemu lub przestarzałego poradnika), w przypadku polegania na firewallu dostawcy, który filtruje tylko IPv4, lub gdy Docker publikuje port z pominięciem UFW. Stan przełącznika można sprawdzić za pomocą grep IPV6 /etc/default/ufw.
Jak sprawdzić, co mój VPS udostępnia w sieci IPv6?
Uruchom sudo ss -tlnp i zwróć uwagę na każdy proces nasłuchujący, którego adres lokalny zaczyna się od [::], co oznacza, że odpowiada on na każdym interfejsie IPv6. Następnie, z innej maszyny, przetestuj publiczny adres IPv6 serwera za pomocą curl -6 -v http://[YOUR:IPV6::ADDR]:PORT/ lub przeskanuj go narzędziem nmap -6 YOUR:IPV6::ADDR. Każdy port otwarty w skanowaniu IPv6, a zamknięty w IPv4, stanowi lukę w zabezpieczeniach.
Dlaczego mogę połączyć się z portem kontenera Docker, mimo że UFW twierdzi, iż jest zablokowany?
Docker wstawia własne reguły firewalla przed regułami UFW w momencie publikacji portu za pomocą -p, dlatego opublikowany port jest dostępny, nawet jeśli ufw status oznacza go jako zablokowany. Dzieje się tak w IPv4, a także w IPv6, jeśli obsługa IPv6 w Dockerze jest włączona. Publikuj porty na konkretny adres, taki jak -p 127.0.0.1:8080:80, lub umieść kontener za reverse proxy i publikuj tylko to proxy.
Czy nadal potrzebuję firewalla IPv6, jeśli mój firewall IPv4 jest poprawnie skonfigurowany?
Tak. IPv4 i IPv6 to oddzielne stosy sieciowe z oddzielnymi regułami firewalla. Idealny zestaw reguł IPv4 nie wpływa na ruch IPv6. Jeśli VPS posiada publiczny adres IPv6 (a posiada go niemal każdy), każda usługa nasłuchująca na :: pozostaje dostępna przez IPv6, dopóki nie zostanie zablokowana regułą firewalla IPv6 lub powiązaniem z interfejsem loopback.
Jak sprawić, by usługa nasłuchiwała tylko na IPv4 lub tylko na localhost?
Ustaw adres powiązania (bind address) w konfiguracji danej usługi. Powiąż usługę z 127.0.0.1 dla samego loopback IPv4 lub z 0.0.0.0 dla wszystkich adresów IPv4 bez nasłuchiwania na IPv6. Postgres używa listen_addresses, SSH używa ListenAddress, a większość serwerów aplikacji udostępnia odpowiednią flagę hosta lub bind. Potwierdź wynik za pomocą sudo ss -tlnp i sprawdź, czy Local Address nie wskazuje już [::].