DROP vs. REJECT
Temat dotyczy konfiguracji firewalli WEWNĄTRZ naszej sieci. Spotkałem się z nim dawno, dawno temu, jak jeszcze zajmowałem się administrowaniem, między innymi administrowaniem urządzeniami sieciowymi, ale wciąż jest żywy. Mogę powiedzieć nawet, że teraz jest bardziej aktualny niż kiedyś, bo w coraz większej ilości sieci są one podzielone na strefy, a samo filtrowanie dotyczy nie tylko ruchu przychodzącego, ale również wychodzącego.
To teraz pytanie – czy używać akcji DROP czy REJECT?
Na czym polega różnica? W przypadku DROP firewall wpuszcza pakiet w /dev/null i nie informuje o tym klienta. Protokół TCP, bo o niego głównie chodzi, był projektowany z myślą o pracy w sieci, która potencjalnie mogła “trochę” nie działać. Na przykład pewne pakiety (datagramy IP) mogły zginąć gdzieś po drodze, zabłąkać się, pójść inną drogą, złapać bliżej nieokreślone opóźnienie. Sam proces nawiązywania połączenia uwzględnia tę sytuację i wysyła pakiet SYN trzy razy (ponawia próbę połączenia 2 razy) zwiększając przy tym czas oczekiwania na pakiet SYN/ACK.
Załóżmy teraz, że jestem komputerem, który znajduje się w sieci, z której dozwolona jest tylko część połączeń sieciowych i przypadkiem wykonuję połączenie TCP na adres, do którego nie mam dostępu. Mój pakiet trafia do /dev/null, a ja nic o tym nie wiem, powtarzam więc próbę jeszcze dwukrotnie (tak bardzo się staram) i dopiero zgłaszam błąd. Konkretnie to błąd zgłasza stos TCP/IP, a aplikacja często próbuje jeszcze raz (grzeczny stos TCP/IP ponownie bardzo się stara nawiązać połączenie), ponownie zgłasza błąd, a aplikacja mówi – sprawdźmy jeszcze raz, może teraz się uda... I dopiero po dłuższym, zauważalnym przez użytkownika czasie, aplikacja w końcu się poddaje.
Na czym polega problem? Przecież firewall zadziałał prawidłowo, nie pozwolił na połączenie, które jest niezgodne z polityką bezpieczeństwa. A skoro jest niezgodne, to po co takie połączenie było nawiązywane? Prawda? Nie do końca.
Załóżmy, że użytkownik chce nawiązać połączenie z wykorzystaniem protokołu SSL (niech będzie – HTTPS) z jakimś serwerem, do którego zgodnie z polityką ma dostęp. Zupełnie przypadkiem niech to będzie Gmail. Serwer przedstawi się wówczas następującym certyfikatem (przy okazji – kto zauważył, że Google sam sobie wystawia certyfikaty?):
Certificate: Data: Version: 3 (0x2) Serial Number: 13:2b:a2:86:00:00:00:00:6f:6d Signature Algorithm: sha1WithRSAEncryption Issuer: C=US, O=Google Inc, CN=Google Internet Authority Validity Not Before: Nov 21 10:10:14 2012 GMT Not After : Jun 7 19:43:27 2013 GMT Subject: C=US, ST=California, L=Mountain View, O=Google Inc, CN=mail.google.com Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (1024 bit) Modulus: 00:c5:85:cf:ca:cf:59:fe:a6:38:fe:2f:50:46:dc: d3:9a:af:18:7d:55:41:1a:28:02:ab:2b:51:c0:70: ca:19:ef:41:0d:4f:ff:8e:7e:83:d8:13:b2:fd:b9: 2f:f1:45:71:87:f4:ab:99:92:79:a1:b4:bf:a6:69: 63:d9:0a:30:12:53:e4:2a:84:27:d2:c1:65:dc:3b: 6d:a8:55:a5:4c:e8:8e:4e:8d:9f:f4:d6:50:30:36: fa:0e:01:37:c5:c7:97:69:84:d0:fd:68:fe:df:15: 50:c4:23:ed:c7:ae:21:17:d0:e9:40:a2:dd:0c:01: 00:b5:00:9f:99:ad:d5:cd:bd Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Extended Key Usage: TLS Web Server Authentication, TLS Web Client Authentication X509v3 Subject Key Identifier: 85:94:6A:2E:D8:64:37:55:3B:16:C3:B3:9D:94:8F:55:3E:AD:B4:8E X509v3 Authority Key Identifier: keyid:BF:C0:30:EB:F5:43:11:3E:67:BA:9E:91:FB:FC:6A:DA:E3:6B:12:24
X509v3 CRL Distribution Points:
Full Name: URI:http://www.gstatic.com/GoogleInternetAuthority/GoogleInternetAuthority.crl
Authority Information Access: CA Issuers – URI:http://www.gstatic.com/GoogleInternetAuthority/GoogleInternetAuthority.crt
X509v3 Basic Constraints: critical CA:FALSE X509v3 Subject Alternative Name: DNS:mail.google.com Signature Algorithm: sha1WithRSAEncryption 9d:d5:c8:40:0b:c8:05:d4:17:94:3e:16:a8:c6:79:9b:6d:eb: 5a:a9:1a:ed:8b:26:54:ee:7e:64:4d:22:29:f0:9e:94:0b:9d: ba:3c:d0:8d:3b:45:23:60:81:69:e7:27:db:fd:40:74:b3:1a: 20:65:37:d6:8a:61:36:a3:ec:fd:2c:f6:8b:ac:aa:93:d1:df: f1:67:20:92:3a:c0:3e:d7:16:11:1f:7b:9f:db:9a:35:2d:ba: ba:1c:5e:eb:3a:d3:e8:38:2c:77:84:c0:e2:81:11:fb:bc:25: 33:5c:1b:14:c4:e4:cf:2d:9c:24:95:d6:67:84:a2:2f:e1:51: ba:7f
By użycie SSL miało sens (pełny), oprogramowanie na tej maszynie musi zweryfikować certyfikat serwera, z którym się łączy. W tym celu musi zbudować ścieżkę (łańcuch) certyfikatów i sprawdzić listy CRL (lub OCSP). I tu niespodzianka, przy takim połączeniu mogą pojawić się dodatkowe połączenia do adresów:
- CRT: http://www.gstatic.com/GoogleInternetAuthority/GoogleInternetAuthority.crt
- CRL: http://www.gstatic.com/GoogleInternetAuthority/GoogleInternetAuthority.crl
System operacyjny i działające na nim aplikacje mogą w trakcie zupełnie normalnej, poprawnej pracy mogą generować duże ilości tego typu prób połączeń. Opisany tutaj przypadek weryfikacji certyfikatu nie jest oczywiście jedynym możliwym przypadkiem takiej sytuacji. W efekcie mogą pojawić się dziwne i irytujące opóźnienia.
Dawno, dawno temu przyszli do mnie programiści pracujący w firmie, w której byłem administratorem. Ale to byli światli programiści, poza objawami problemu potrafili powiedzieć dużo, między innymi to, na jakiej funkcji API program zawisa. W tamtym przypadku problem był najbardziej widoczny/uciążliwy w Explorerze, na przykład przy oglądaniu szczegółów podpisanego cyfrowo pliku. Ta akcja wywoływała weryfikację podpisu, weryfikacja podpisu wywoływała weryfikację certyfikatów użytych do podpisu, co z kolei skutkowało próbą pobrania dodatkowych informacji z sieci zewnętrznej i w rezultacie – opóźnieniem, którego mechanizm powstania wcześniej opisałem.
Jak sobie poradzić z tym problemem? Sprawa jest dość prosta – wystarczy zmienić DROP na REJECT. Firewall blokujący ruch nadal spuszcza pakiet do /dev/null, ale jest przy tym na tyle uprzejmy, że informuje o tym fakcie klienta, najczęściej pakietem RST. Stos TCP/IP nawiązujący połączenie dostaje ten pakiet RST, wie więc, że połączenie nie może być nawiązane i nie próbuje nawiązywać go ponownie. Otrzymanie pakietu RST w tym przypadku oznacza, że pakiet SYN nie zabłądził po drodze, tylko druga strona nie chce z nami gadać (w tym przypadku akurat, że firewall na takie połączenie nie pozwala, ale akurat nasz stos TCP/IP tego już wcale nie musi być świadomy).
A tak zupełnie przy okazji – kto z czytelników pamięta, dlaczego za starych czasów jak się konfigurowało zewnętrzny firewall i ustawiało domyślną regułę na DROP, to robiło się wyjątek dla portu 113 TCP i ustawiało wówczas REJECT? :)
P.S. Zwracam uwagę, że ustawienie REJECT rozwiązuje tylko jeden problem, wcale nie najistotniejszy. Pytanie – co się stanie, jeśli certyfikat serwera, z którym się łączymy, trafił ostatnio na CRL?
Druga sprawa – jeśli na zewnętrznym firewallu też mamy DROP, możemy nieświadomie uczestniczyć w ataku DoS. W jaki sposób? Pytanie – ile razy serwer odpowiada SYN/ACK na otrzymany pakiet SYN, jeśli nie dostanie ACK? Patrz też: SYN cookies.
Oryginał tego wpisu dostępny jest pod adresem DROP vs. REJECT
Autor: Paweł Goleń