Ściana już nie parzy

Zapory sieciowe (firewall) stały się standardowym wyposażeniem sieci, a mimo to fala zagrożeń płynących z Internetu wciąż wzrasta. Zamiast je forsować, włamywacze sięgają po techniki, dzięki którym obecność zapory, czy nawet kilku, niewiele znaczy. Stawienie czoła zagrożeniom jest możliwe, ale wymaga pewnej mobilizacji - nie w kwestii narzędzi, lecz ludzi.

Zapory sieciowe (firewall) stały się standardowym wyposażeniem sieci, a mimo to fala zagrożeń płynących z Internetu wciąż wzrasta. Zamiast je forsować, włamywacze sięgają po techniki, dzięki którym obecność zapory, czy nawet kilku, niewiele znaczy. Stawienie czoła zagrożeniom jest możliwe, ale wymaga pewnej mobilizacji - nie w kwestii narzędzi, lecz ludzi.

Historia rozwoju większości aplikacji zawiera etapy usuwania krytycznych błędów, w tym także tych związanych z bezpieczeństwem. Napisanie dużego, skomplikowanego programu tak, by był wolny od błędów, jest skrajnie trudne, w zasadzie niemożliwe. Skutki tych błędów są widoczne w różny sposób - od załamania aplikacji - owo charakterystyczne okienko programu Dr Watson albo wiadomość: "Segmentation fault, core dumped", poprzez jej nieprzewidywalne zachowanie, aż po stan, który umożliwia przejęcie kontroli nad całym systemem.

Przyczynami lwiej części błędów są niedoróbki powstające z winy programistów, które można bardzo prędko usunąć. Dużo gorsze skutki mają błędy protokołów komunikacyjnych albo też złych założeń konstrukcji oprogramowania, co wiąże się z błędami w projektowaniu. O ile zrobienie stosownej łaty naprawiającej konkretny błąd programisty jest dość proste w skali projektu (dowodzą tego choćby bardzo szybkie reakcje środowiska open source czy producentów komercyjnych na konkretne zgłoszenia), o tyle naprawienie błędu wykraczającego poza pojedynczą bibliotekę czy aplikację wchodzącą w skład większego systemu jest naprawdę trudne.

Aby zobaczyć, czym się to kończy, wystarczy zajrzeć na strony serwisu Knowledge Base Microsoftu. Ciągle znajdowane są kolejne błędy. Każdy z nich skutkuje co najmniej możliwością ataku DoS, a nierzadko grozi także przejęciem kontroli nad komputerem. Wydaje się zatem, że szkodliwa jest nie tyle "dziurawość" poszczególnych aplikacji, ale ich bardzo ścisła integracja - to dlatego każdy błąd ma potencjalnie bardzo poważne skutki. Trudno jednak, aby było inaczej, skoro w środowisku Windows nie korzysta się z powszechnie używanej w systemach typu Unix opcji chroot(). Inna konstrukcja systemu wymusza postawienie bardzo wysoko poprzeczki bezpieczeństwa dla każdego z procesów systemowych Windows.

Firewall nie wystarczy

Decydenci, którzy z reguły nie znają niuansów systemów zabezpieczeń, sądzą, że kilka szeregowo ustawionych zapór sieciowych gwarantuje sieci bezpieczeństwo. Niestety, są w błędzie. Czasami nawet flagowy produkt zainstalowany na specjalnie "utwardzonym" systemie nie uchroni przed wszystkimi możliwymi atakami. Atakujący chwytają się zazwyczaj metod dających najszybsze efekty i zamiast prób na poziomie sieci, wolą próbować wykorzystać błędy popełniane na poziomie aplikacji.

Bywa, że wykorzystanie warstwy aplikacyjnej nie powoduje interwencji zapory - atak wygląda tak, jak typowe zapytanie do serwera WWW, nie ma więc powodu, by wszczynać alarm. Zapór nie tworzy się na potrzeby źle napisanych aplikacji, ale by chronić systemy przed zagrożeniami czyhającymi w manipulacji protokołami sieciowymi.

Pół biedy, gdy ruch od klientów do serwera jest przenoszony za pomocą zwykłych odwołań na port 80 w sesjach HTTP, a aplikacja nie zawiera dyskredytujących ją szkolnych błędów. Gdy jednak cały ruch jest szyfrowany za pomocą SSL, zawartość sesji nie jest widoczna dla filtra pakietów. Nie ma więc mowy o jakiejkolwiek ochronie - zwłaszcza przed atakami typu SQL injection, polegającymi na wywołaniu przetwarzania zapytania powodującego powstanie błędów logicznych, desynchronizacji danych lub nawet dokonania na niej nieautoryzowanych operacji.

Oczywiście poprawnie napisana aplikacja zawiera stosowne mechanizmy zabezpieczenia na poziomie bazy, które uniemożliwią wykonanie groźnych poleceń. Niemniej, jeśli zdalny włamywacz przechwyci tożsamość prawowitego użytkownika, będzie mógł na bazie danych wykonać każdą operację mieszczącą się w zestawie uprawnień. Z praktyki wynika, że często są to uprawnienia bardzo duże, a zatem i skutki mogą być poważne.

Abecadło bezpieczeństwa

Po raz kolejny nasuwa się smutny wniosek. Zagrożenia wynikają nie tyle z błędów w aplikacjach, ile ze złych założeń poczynionych na etapie projektowania. Dotyczy to zwłaszcza poziomu wzajemnego zaufania pomiędzy poszczególnymi komponentami. Aby wyeliminować zagrożenia warstwy aplikacyjnej, najlepiej jest skonstruować aplikację w sposób uniemożliwiający wykonanie ryzykownych operacji.

Oto minimalne warunki, jakie powinna spełniać aplikacja bezpieczna:

  • Aplikację należy tworzyć w sposób modułowy - analiza mniejszych modułów jest prostsza - łatwiej jest ją testować i wychwytywać błędy.
  • Procesy powinny komunikować się za pomocą ściśle ustalonych zasad.
  • Każdy proces musi pracować na możliwie niskich uprawnieniach systemu operacyjnego. Na przykład jeśli modułowo tworzony program ma się komunikować z siecią słuchając na tzw. niskim porcie (np. 25), to uprawnienia systemowe konieczne do wykonania tam operacji bind() powinien mieć tylko ten proces, pozostałym procesom nie są one potrzebne. W taki modelowy sposób działa serwer pocztowy qmail. Od kilku lat nie znaleziono żadnej poważnej dziury w nim samym (nadal oferowana jest nagroda).
  • Dobrze skonstruowana aplikacja powinna mieć wydzielony proces nadrzędny, służący kontroli i audytowi pozostałych procesów. Dodawanie takiej funkcji "później" to nieporozumienie - trzeba ją przewidzieć od razu.
  • Aplikacja powinna każdorazowo sprawdzać integralność ładowanych bibliotek systemowych. Bardzo dobrym pomysłem jest sprawdzenie sumy kontrolnej (minimum MD5, ale lepiej mocniejszej) przy jej starcie. Takie sprawdzenie jest bardzo łatwe i szybkie. W przypadku modernizacji bibliotek systemowych administrator musi dokonać aktualizacji bazy skrótów, ale nie jest to czynność niegodna administratora. Alternatywą jest rezygnacja z korzystania z większości bibliotek systemowych. Tą drogą poszedł prof. D. J. Bernstein podczas tworzenia qmail - jak widać, przynosi to dobre efekty, chociaż jest pracochłonne i wymaga szczegółowego audytu kodu.
  • Podczas projektowania należy przewidzieć, że na dowolnym etapie działania programu na wejściu funkcji mogą pojawić się fałszywe dane.
  • Jeśli komponenty aplikacji komunikują się przez sieć, komunikacja ta powinna być szczególnie chroniona, by z jej wewnętrznymi komponentami nie można było nawiązać połączenia z jej otoczenia. Wagę tej kwestii udowodnił wirus SQL Slammer, wykorzystując dostępny z zewnątrz port komunikacyjny SQL Servera. Gwoli sprawiedliwości trzeba powiedzieć, że na ataki tego typu podatny okazał się także serwer Oracle.
  • Zapytania do bazy powinny być chronione. W zaawansowanych systemach należy przewidzieć mechanizm sprawdzający poprawność składni, parametrów, długości itp. charakterystyki. Podejrzane są wszystkie "niepotrzebne" znaki - myślniki, średniki, znaki niemieszczące się w ustalonym zakresie itp.
  • Każdy moduł korzystający z sieci musi być tak skonstruowany, by skutki ataku dokonanego za jego pomocą były jak najmniejsze. Chodzi zwłaszcza o to, by uprawnienia ustalać na poziomie poszczególnych tabel, a nawet ich części, a nie całej bazy. Podobnie uprawnieniom do odczytu nie powinny automatycznie towarzyszyć uprawnienia do zapisu - to oznacza więcej pracy dla administratora, ale podnosi poprzeczkę dla włamywaczy.
Jeśli nie ma takiej możliwości, trzeba uciec się do rozwiązania, które analizowałoby zapytania do bazy i na podstawie dodatkowych informacji z serwera WWW (na przykład IP klienta czy inne) i blokowało te, które mogą stanowić zagrożenie. Trzeba jednak zwrócić uwagę, że ochrona na poziomie uprawnień do bazy danych i kontrola zapytań do niej to nie to samo. Dopiero oba te zabezpieczenia razem dają podwyższenie bezpieczeństwa danych w bazie. A zatem:

  • Należy przewidzieć rezerwowe systemy zabezpieczenia, np. stosować replikację, by zniszczenie bazy przez włamywacza sieciowego nie powodowało utraty wszystkich danych.
  • Należy założyć najczarniejszy scenariusz, choćby taki, że intruz z laptopem będzie chciał skorzystać z połączenia bezpośrednio do bazy (np. próba włamania za pomocą ODBC i Accessa). Typowym zabezpieczeniem jest tu stosowanie statycznego ARP i restrykcyjnego filtra pakietów, a także ustawienia filtrów na przełącznikach. W niektórych prostych instalacjach można zastosować dedykowany interfejs sieciowy połączony skrosowanym kablem. Ta bardzo prosta sztuczka nieraz udowadniała swoją skuteczność.
  • Należy rejestrować logi aplikacji i bazy oraz poddawać je regularnej analizie.
Słuchajcie, a znajdziecie

Analiza protokołów za pomocą dedykowanych programów (sniffer) to normalne zajęcie administratora. Półświatek włamywaczy miał wiele czasu i motywacji, by na podstawie ogólnie dostępnych snifferów zbudować programy podsłuchujące praktycznie wszelki ruch w sieci. Dla nich nie istnieją "zamknięte" protokoły.

Sniffing ma wiele zalet dla włamywacza - jest łatwy w wykonaniu przy typowej konfiguracji sieci, trudny do wykrycia i szybko dostarcza dużych ilości rzeczywiście użytecznych informacji. Jedyną skuteczną obroną przed podsłuchem sieci jest szyfrowanie połączenia za pomocą dobrego algorytmu z długim kluczem, co w przypadku sieci LAN jest niezwykłą rzadkością, zaś w sieciach WAN szyfrowany jest jedynie tunel transportowy - tuż za bramką VPN dane znów są jawne.

Wykrycie sniffera jest trudne i może łatwo ujść uwadze audytorów. Sniffer zainstalowany na serwerze baz danych jedynie nasłuchuje - nie wywołuje żadnych połączeń. Nie dokonuje też żadnych połączeń do bazy danych, zatem najczęściej wykonywany audyt połączeń do bazy danych nie wykaże wątpliwości.

Gdy sniffer zostanie wbudowany w którąś z usług sieciowych Windows za pomocą podmienionej biblioteki, staje się jeszcze trudniejszy do wykrycia. Proces svchost.exe nie sprawdza co dokładnie uruchamia i czy ten program nie uległ modyfikacji. Zdarza się, że konkretnej usługi nie daje się zablokować na zaporze sieciowej, ponieważ wszystkie programy usługowe są widoczne właśnie jako svchost.exe. Włamywacze doszli już do takiej wprawy, że potrafią ukryć przed systemem operacyjnym fakt, że karta sieciowa działa w trybie nasłuchu (promiscuous).

Jedynym wyjściem jest zatem szyfrowanie połączenia za pomocą powszechnie znanych algorytmów szyfrujących i ustawienie odpowiednio długiego klucza. Stosowanie zamkniętych algorytmów o krótkim kluczu jest zawsze czerwonym światłem alarmowym dla kryptologów - dlatego lepiej zaufać sprawdzonym rozwiązaniom, takim jak 3DES czy SSL. Nie zapewniają maksymalnego bezpieczeństwa, ale są proste w realizacji i wystarczająco skuteczne.

W celu komercyjnej reprodukcji treści Computerworld należy zakupić licencję. Skontaktuj się z naszym partnerem, YGS Group, pod adresem [email protected]

TOP 200