Preorder drugiego tomu książki sekuraka: Wprowadzenie do bezpieczeństwa IT. -15% z kodem: sekurak-book
Firmowy serwis internetowy – rozwiązania opensource kontra dedykowane – w kontekście bezpieczeństwa (cz. 4.)
Szczegółowa analiza wymagań bezpieczeństwa
Zanim podejmiemy decyzję, czy zastosujemy sprawdzone, ogólnodostępne rozwiązanie opensource, czy też zlecimy budowę nowego, kompletnego systemu od podstaw, musimy przeprowadzić szczegółową analizę, jakie tak naprawdę wymagania odnośnie zabezpieczeń stawiamy przed naszym projektem. Punktem wyjścia będzie tutaj określenie:
- do jakich zasobów chcemy umożliwić dostęp z poziomu aplikacji (dane przechowywane w bazie SQL, pliki do pobrania),
- kto będzie z aplikacji korzystał (tylko pracownicy, kontrahenci czy internauci odwiedzający serwis, często są to wszystkie te wymienione grupy).
Gdy mamy już jasno zdefiniowane podstawowe założenia, możemy przystąpić do szczegółów. Dokument Application Security Verification Standard organizacji OWASP (ASVS) definiuje cztery poziomy weryfikacji aplikacji webowych pod kątem bezpieczeństwa. Określone poziomy definiują sposoby, w jakich dokonuje się wspomniana wcześniej weryfikacja (im wyższy poziom, tym aplikacja musi spełnić bardziej zaostrzone kryteria, na najwyższym poziomie obejmuje to np. ręczną analizę kodu źródłowego w poszukiwaniu podatności).
Proces tworzenia nowego systemu objęty jest pojęciem znanym jako SDLC (Software Development Life Cycle – cykl życiowy projektowania/tworzenia oprogramowania). Proces SDLC oparty na ASVS jednoznacznie wskazuje, na jakim jego etapie musimy zadbać o zdefiniowanie reguł bezpieczeństwa – powinien poprzedzać wszystkie następne etapy tworzenia aplikacji, czyli tak naprawdę stanowić punkt wyjściowy do rozpoczęcia całego procesu (na poniższym schemacie zaznaczyłem go czerwoną ramką):
Przyjrzyjmy się teraz, w jaki sposób ASVS opisuje konkretne reguły bezpieczeństwa oraz jakich wskazówek udziela w kontekście weryfikacji aplikacji na określonym poziomie.
1. Reguły bezpieczeństwa
Jako przykład do analizy posłuży nam mechanizm autoryzacji użytkowników. Opierając się na wcześniejszych ustaleniach, decydujemy, że:
- system ma uniemożliwiać enumerację nazw użytkowników,
- system ma blokować możliwość powtarzania nieudanych autoryzacji,
- system ma zapewniać możliwie najwyższy poziom zabezpieczenia haseł, poprzez funkcje skrótu z użyciem tzw. soli (salt),
- wszystkie operacje muszą być logowane (zapisywane) w systemie zbierającym logi (zapis historii działań w serwisie).
W dokumencie ASVS te wymagania znajdują się w sekcji V2:
Jest to tylko część listy odpowiedzialnej za mechanizm autoryzacji użytkowników. Większość z nich zamyka się w przedziale 1. i 2. poziomu ASVS. Ostatecznie punkt V2.13 (dotyczący tworzenia skrótów haseł z użyciem soli) jednoznacznie określa poziom zbezpieczeń naszej aplikacji na trzeci:
V2.13 ASVS
Zgodnie z powyższym musimy odpowiednio zweryfikować wcześniejsze analizowane rozwiązania opensource. Czym są skróty (tzw. funkcje haszujące), można przeczytać m.in. na stronie Wikipedii poświęconej omówieniu tego zagadnienia.
2. Wybrane przykłady
Aby podkreślić znaczenie punktu V2.13 ASVS dla bezpieczeństwa naszej przyszłej aplikacji, posłużę się małym przykładem, jak cyberprzestępcy „odczytują” hasła zapisane w postaci skrótów MD5.
Wyobraźmy sobie, że jesteśmy administratorem takiego serwisu. Nasze hasło to „123pass”. Ciąg MD5 dla naszego hasła, zapisany w bazie SQL to 96b9c62c86f35c209c5b8c302ba34175. Po wklejeniu ciągu do przeglądarki Google szybko odnajdujemy pasującą parę hasło-skrót MD5:
Na pewno nie spodziewaliśmy się tam ujrzeć kilku wyników zawierających nasz skrót wraz z odpowiadającym mu hasłem w postaci czystego tekstu.
W Internecie istnieje wiele baz skrótów MD5 oraz SHA1 wraz z odpowiadającymi im tekstami w postaci jawnej (np. http://www.md5decrypter.co.uk/ ). Jeśli cyberprzestępca nie odnajdzie tam żadnego odpowiadającego podanemu skrótowi hasła, zawsze może posłużyć się jedną ze wspomnianych wcześniej metod wykrywania kolizji skrótów.
Wróćmy do analizy i sprawdźmy, jak wyglądają fragmenty kodu systemów WordPress oraz Joomla! odpowiedzialne za haszowanie haseł użytkowników.
W WordPress są to metody w klasie PasswordHash (/wp-includes/class-phpass.php). Przyjrzyjmy się dokładnie metodzie HashPassword():
215 function HashPassword($password) 216 { 217 $random = ''; 218 219 if (CRYPT_BLOWFISH == 1 && !$this->portable_hashes) { 220 $random = $this->get_random_bytes(16); 221 $hash = 222 crypt($password, $this->gensalt_blowfish($random)); 223 if (strlen($hash) == 60) 224 return $hash; 225 } 226 227 if (CRYPT_EXT_DES == 1 && !$this->portable_hashes) { 228 if (strlen($random) < 3) 229 $random=$ this->get_random_bytes(3); 230 $hash = 231 crypt($password, $this->gensalt_extended($random)); 232 if (strlen($hash) == 20) 233 return $hash; 234 } 235 236 if (strlen($random) < 6) 237 $random=$ this-> get_random_bytes(6); 238 $hash = 239 $this->crypt_private($password, 240 $this->gensalt_private($random)); 241 if (strlen($hash) == 34) 242 return $hash; 243 244 # Returning '*' on error is safe here, but would _not_ be safe 245 # in a crypt(3)-like function used _both_ for generating new 246 # hashes and for validating passwords against existing hashes. 247 return '*'; 248 }
Jak można zauważyć (fragment kodu 239-242), domyślnie wynikiem działania jest skrót w postaci (przykładowo) $P$BZtq.o.Pu99rMMBGbJ640XUZ2kVf3v.
Nie jest to żaden znany format skrótów (MD5, SHA1) i nie pozwala na odnalezienie hasła zapisanego w postaci czystego tekstu (plain text) w prosty sposób (np. z wykorzystaniem wyszukiwarki Google). Możemy więc wstępnie założyć, że mechanizm haszowania haseł systemu WordPress spełnia stawiane naszej aplikacji wymagania.
Kolej na Joomla!. Oto fragment pliku /libraries/joomla/crypt/password/simple.php zawierający definicję klasy JCryptPasswordSimple – jedną z jej metod jest create():
public function create($password, $type = JCryptPassword::BLOWFISH) { switch ($type) { case JCryptPassword::BLOWFISH: $salt = $this->getSalt(22); if (version_compare(PHP_VERSION,'5.3.7') >= 0) { $prefix = '$2y$'; } else { $prefix = '$2a$'; } $salt = $prefix . str_pad($this->cost, 2, '0', STR_PAD_LEFT) . '$' . $this->getSalt(22); return crypt($password,$salt); case JCryptPassword::MD5: $salt = $this->getSalt(12); $salt = '$1$' . $salt; return crypt($password, $salt); case JCryptPassword::JOOMLA: $salt = $this->getSalt(32); <strong> return md5($password . $salt) . ':' . $salt; </strong> default: throw new InvalidArgumentException(sprintf('Hash type %s is not supported',$type)); break; } }
Także w przypadku Joomla! wymagania stawiane w punkcie V2.13 dokumentu ASVS są spełnione, gdyż metoda create() zwraca hasz składający się z 32-znakowego ciągu MD5 zawierającego skrót hasła i soli oraz (po znaku ’:’) samą sól.
Jak widzimy zatem, oba systemy w tym punkcie wpasowują się w przyjętą przez nas strategię bezpieczeństwa zakładającą, że aplikacja ma spełniać poziom 3. wymagań. W analogiczny sposób należy dokonać weryfikacji pod kątem pozostałych wymagań poziomu 3. ASVS, chyba, że któreś z naszych założeń wymaga spełnienia poziomu 4. Wtedy automatycznie wszystkie założenia dotyczące bezpieczeństwa należy dostosować do najwyższego, czwartego poziomu.
Rzućmy jeszcze okiem na przykład systemu CMS, który nie spełni naszych wymagań: CMS MadeSimple. W pliku /admin/adduser.php znajduje się kod odpowiedzialny za dodawanie nowego użytkownika. Zaglądając do instrukcji na poniższym listingu (fragment pliku adduser.php), która odpowiada za zapis danych do bazy, można zauważyć, że hasło zapisywane jest jako czysty hasz MD5 – nie jest wykonywana żadna dodatkowa operacja, poza oczyszczeniem z niebezpiecznych znaków przekazanego z formularza tekstu reprezentującego hasło:
(...) if ($validinfo) { #$new_user_id = $db->GenID(cms_db_prefix()."users_seq"); #$query = "INSERT INTO ".cms_db_prefix()."users (user_id, username, password, active, create_date, modified_date) VALUES ($new_user_id, ".$db->qstr($user).", ".$db->qstr(md5($password)). ", $active, '" .$db->DBTimeStamp(time())."', '" .$db->DBTimeStamp(time())."')"; #$result = $db->Execute($query); (...)
Najprawdopodobniej w podobny sposób potraktowano w nim wiele innych kwesti związanych z bezpieczeństwem i nie ma szans, by na tym etapie osiągnął docelowy poziom 3. według dokumentu ASVS. Wymagałby od nas wielu żmudnych przeróbek i implementacji ESAPI oraz PHPIds. Biorąc pod uwagę sposób, w jaki CMS MadeSimple został napisany (brak scentarlizowanego mechanizmu obsługującego zapytania do bazy), koszty takich modyfikacji byłyby trudne do oszacowania.
W przypadku aplikacji dedykowanej mamy nieco ułatwione zadanie – wszystkie mechanizmy są implementowane od podstaw. Dzięki temu mamy pełną kontrolę nad każdym aspektem związanym z realizacją założonej przez nas polityki bezpieczeństwa, poziomu zabezpieczeń aplikacji, testowaniem aplikacji i wprowadzanymi zmianami.
Dodatkowe zabezpieczenia infrastruktury dla aplikacji internetowej
Bardzo ważnym elementem bezpiecznego serwisu firmowego jest środowisko, w jakim aplikacja działa. Z reguły mamy do czynienia z serwerem WWW (Apache, nginx, serwery aplikacji JEE, IIS itp.) oraz z serwerem przechowującym dane w relacyjnej bazie danych (MySQL, PosgreSQL, Oracle, DB2, MSSQL). Na zakończenie przedstawię rozwiązanie skupiające się na warstwie danych naszej aplikacji – firewallu bazodanowym GreenSQL. Co prawda jest to narzędzie komercyjne, ale zapewnia zabezpieczenie serwera bazodanowego niezależnie od zabezpieczeń zastosowanych w samej aplikacji.
GreenSQL eliminuje zagrożenia związane z błędami SQL Injection oraz blokuje nieautoryzowane próby dostępu do bazy danych. Może posłużyć także jako dodatkowy mechanizm cache dla serwera bazodanowego. Podobnie jak ESAPI, GreenSQL jest wieloplatformowy, ale w tym wypadku dotyczy to systemów relacyjnych baz danych – system wspiera MS SQL Server, MySQL, MariaDB, PostgreSQL, a także rozwiązania działające w chmurach: Microsoft SQL Azure oraz Amazon WebServices.
Miejsce firewalla bazodanowego w łańcuchu bezpieczeństwa serwisu przedstawia poniższa ilustracja:
CRACKER –> PHPIds –> ESAPI –> aplikacja/biblioteki własne frameworka (np. ZF, Symfony) –> GreenSQL Firewall –> DANE (serwer SQL)
Nie należy zapominać także o prawidłowym skonfigurowaniu:
- serwera WWW,
- interpretera PHP bądź innego środowiska, w którym napisany jest serwisw
- serwera bazodanowego.
Szczegóły dotyczące tych zagadnień wychodzą poza ramy niniejszego artykułu – zainteresowanych odsyłam do informacji zamieszczonych w Internecie, na stronach dokumentacji producentów czy na fora poświęcone bezpieczeństwu informatycznemu.
Bardzo ważną rzeczą jest też zapewnienie sobie informacji na wypadek, gdyby jednak komuś udało się spenetrować nasz system. Logujmy całą aktywność serwisu, szczególną uwagę zwracając na odbiegające od normy sygnały. Mogą to być próby skanowania infrastruktury sieciowej, nietypowe żądania HTTP powodujące błędy serwera, nagły wzrost obciążenia serwera, kolejne nieudane próby logowań z określonej puli adresów IP. Każdy taki incydent może wskazywać na wstępny rekonesans lub początek ataku na nasz serwis. Jeśli zareagujemy odpowiednio wcześnie, mając zestaw informacji zapisanych w logach, szybko naprawimy lukę i zapobiegniemy stratom.
Z kolei po ataku zakończonym powodzeniem kompletne, szczegółowe logi mogą pomóc ustalić sprawcę (przestępstwa internetowe podlegają w Polsce ściganiu na wniosek pokrzywdzonego, a konsekwencje są dokładnie określone w art. 267 Kodeksu Karnego).
Podsumowanie
Proces tworzenia bezpiecznego serwisu firmowego nie jest sprawą prostą. Jest wiele aspektów, na które należy zwrócić uwagę. Zapewnienie odpowiedniego poziomu bezpieczeństwa to tylko jeden z elementów układanki, która jako całość powinna dostarczyć nam rozwiązania, którego oczekiwaliśmy.
- Zdefiniujmy, jaką rolę będzie pełniła aplikacja – czy będzie to jedynie wizytówka, czy będziemy przy jej pomocy realizować cele biznesowe, czy przykładowo będzie wsparciem standardowych kanałów sprzedaży czy dystrybucji.
- W zależności od tego określmy, jakie informacje będą dostępne z poziomu aplikacji i dla kogo; ustalmy role użytkowników aplikacji (administrator, użytkownik, klient, dostawca itp.) i na tej podstawie ustalmy listę zasobów dostępnych dla każdej grupy.
- Szczegółowo określmy, posiłkując się wytycznymi ASVS, jakiego poziomu zabezpieczeń oczekujemy od aplikacji.
- Sprawdźmy, czy istnieje już rozwiązanie nas satysfakcjonujące – czy spełnia wszystkie wymogi funkcjonalne, czy posiada wsparcie techniczne, czy jest aktualizowane.
- Zweryfikujmy poziom bezpieczeństwa takiego rozwiązania, kierując się wytycznymi ASVS dla oczekiwanego poziomu.
- Jeśli znalezione rozwiązanie spełnia wymogi z dwóch poprzednich punktów, możemy przystąpić do jego wdrażania; jeśli nie, należy rozważyć zakup oprogramowania komercyjnego lub opisane w niniejszym opracowaniu zamówienie rozwiązania dedykowanego.
- Jeśli zdecydowaliśmy się na rozwiązanie dedykowane pozostaje nam jedynie przekazanie wykonawcy pełnej specyfikacji funkcjonalnej oraz technicznej wraz ze wskazaniem, jakie warunki z zakresu zabezpieczeń musi spełnić zamawiany kod.
- Ostatnim etapem może być zlecenie przeprowadzenia testów penetracyjnych aplikacji oraz całej infrastruktury serwerowej w celu potwierdzenia w praktyce, czy aplikacja spełnia wszystkie stawiane przed nią zadania oraz czy jej zabezpieczenia odpowiadają naszym oczekiwaniom.
Pamiętajmy, że samo zbudowanie, przetestowanie i uruchomienie aplikacji internetowej nie kończy całego procesu. W przypadku gotowego rozwiązania musimy dbać o aktualizacje, szczególnie te związane z poprawkami dotyczącymi zabezpieczeń. Pamiętajmy też, że cyberprzestępcy wciąż wymyślają nowe techniki ataków i zabezpieczenia, które dziś wydają się w pełni realizować swoje zadania, za jakiś czas mogą okazać się niewystarczające.
Należy też zwrócić uwagę na pewne momenty krytyczne w cyklu życia serwisu. Są to z reguły duże modyfikacje, polegające na dodaniu nowej funkcjonalności bądź istotne ingerencje w już istniejące. Każda taka zmiana niesie ze sobą ryzyko naruszenia przyjętej polityki zabezpieczeń (przykładowo poprzez modyfikację systemu autoryzacji), do czego często dochodzi nawet przypadkowo, niejako przy okazji wprowadzanych zmian. Szczególnie w przypadku systemów dedykowanych, gdy z jakiś powodów wsparcie takiego systemu powierzamy nowej firmie, zachodzi duże ryzyko głęboko posuniętych zmian, co niejednokrotnie może całkowicie zniweczyć wszystkie dotychczasowe wysiłki ukierunkowane na stworzenie spójnego, solidnego i odpornego na włamania systemu.
Zakończenie
Jest wiele przykładów na to, jak zaniedbanie podstawowych kwestii może nadszarpnąć reputacją firmy i narazić ją na wielomilionowe straty. Głośnym przykładem z ostatnich lat może być choćby firma Sony, dla której atak na bazy danych platformy Sony Playstation Network zakończył się wyciekiem około 77 milionów loginów i innych danych z kont użytkowników SPN (Sony Playstation Network). Straty finansowe związane z koniecznością wyłączenia całej sieci SPN na kilka tygodni, utrata reputacji przez Sony jako firmę i odpływ klientów do konkurencyjnych platform, kosztowały ten koncern kilkadziesiąt, jeśli nie kilkaset milionów oraz zmusiły Zarząd do publicznych przeprosin (Sony apologizes, details PlayStation Network attack).
Opierając swój biznes na aplikacjach sieciowych, pamiętajmy o bezpieczeństwie – serwis internetowy to produkt czysto wirtualny, ale straty wynikające z zakończonego powodzeniem ataku – są jak najbardziej realne.
– Rafal “bl4de” Janicki [bloorq<at>gmail.com]
Jeszcze informacyjnie – to już ostatnia część cyklu.
A miało być o scrypcie i podwójnym hashowaniu :((
@józek
Miałem na myśli niebezpieczeństwa używania MD5 i SHA1 – nie zrozumieliśmy się :)
Dzięki wielkie za ten świetny artykuł! :)
Świetna seria artykułów ;)
konfigi tez mialy byc, a skonczylo sie na teorii
dopiero się zaczęło ;) kolejna część już jest, ale pracujemy nad jej … opracowaniem.
Świetna seria. Dzięki za informację, temat rzeka ale łatwiej będzie rozmawiać z Klientem jak to przeczyta :)
@nDragon
Miło wiedzieć, że komuś się przyda ten tekst :)
Jeśli masz jakieś pytania odnośnie tekstu czy tematu – zapraszam do kontaktu.