Preorder drugiego tomu książki sekuraka: Wprowadzenie do bezpieczeństwa IT. -15% z kodem: sekurak-book
Owasp Dependency Check – Szybki start
W zeszłym roku miałem przyjemność gościć jako prelegent na trójmiejskim wydarzeniu Tech 3camp, gdzie miałem okazję opowiedzieć trochę o OWASP Dependency Check. Dziś jednak postanowiłem podzielić się bardziej tutorialową wersją mojej prezentacji i korzystając z okazji przybliżyć użytkownikom to narzędzie oraz jego możliwości. Jeśli ktoś jest zainteresowany prezentacją, nagranie znajduje się tutaj: https://vimeo.com/346896525
OWASP Dependency Check jest to projekt open source, który zapewnia wsparcie developerów w cyklu wytwarzania oprogramowania na platformach Java oraz .Net. W założeniach ma to podnieść świadomość zespołów programistycznych i managementu o potencjalnych lukach, jakie mogą pojawić się w projekcie, co może prowadzić do niejako „zainfekowania” oprogramowania i zwiększenia jego podatności na ataki.
Od strony technicznej OWASP DC jest kolejną zależnością (dependencją) w projekcie mającą za zadanie, w odpowiednio skonfigurowanych warunkach kolejno:
- połączyć się z ogólnodostępnymi bazami podatności: CVE (Common Vulnerabilities and Exposures) https://cve.mitre.org/ oraz NVE (National Vulnerability Database) https://nvd.nist.gov/;
- pobrać sygnatury problemów na dysk maszyny gdzie wykonywana jest kompilacja z użyciem narzędzi takich jak np. maven, gradle;
- porównać podatności w konkretnych wersjach dependencji do tych udostępnionych w bazie CVE/NVE;
- w podsumowaniu otrzymujemy listę problematycznych bibliotek z wersjami, które użyte są w projekcie wraz z opisem podatności.
Teraz kilka uwag krytycznych z punktu widzenia użytkownika tego narzędzia, czyli najczęściej programistów. To, że jakaś z używanych przez Was zależności jest podatna na atak, nie znaczy, że w Waszej aplikacji taki atak będzie skuteczny lub w ogóle możliwy. Dlaczego?
Biblioteki, których używamy jako programiści, są różnej wielkości projektami składającymi się z wielu klas i metod. Zazwyczaj jest tak, że jeśli mamy w projekcie jakąś zależność, to nie wykorzystujemy 100% kodu, który w takiej bibliotece jest dostępny. Innym razem kod jakiego używamy nie będzie wywoływany jawnie przez użytkownika, a np. poprzez jakąś dodatkową warstwę, w której programista może część z tych luk załatać.
Dlatego też nie powinniśmy panikować gdy okaże się, że używamy wersji biblioteki w której wykryto podatności – w takim przypadku trzeba sprawdzić, czy w kodzie naszej aplikacji używamy podatnej części kodu zależności. Jeśli jej używamy, to przed podjęciem dalszych kroków powinniśmy spróbować wykorzystać taką podatność w testowej wersji naszej aplikacji (bazy błędów często zawierają sposób odtworzenia ataku). Dopiero jeśli powtórzenie ataku jest możliwe powinniśmy bić na alarm – wcześniej zgłaszanie problemu managerowi niekoniecznie będzie uzasadnione.
Warto również dodać, że bazy danych błędów są na bieżąco aktualizowane – więc jeśli obecnie korzystacie z OWASP DC i nie macie raportu o znalezionych problemach, nie oznacza to, że np. już jutro ten stan rzeczy się nie zmieni. Uczulam na to i jednocześnie wskazuję, że efektywne użycie tego narzędzia wymaga ciągłego monitorowania wyników.
Zanim zaczniemy część tutorialową i konfigurację wraz z analizą na przykładzie jednego z moich małych projektów chcę Was uczulić, że pobranie baz błędów i analiza w przypadku świeżo ściągniętego projektu może zająć nawet kilkanaście minut. Dlatego też rekomenduję używanie tego dodatku w konkretnych momentach. Najlepiej wyszczególnić dla niego osobny build w narzędziu CI/CD, tak abyśmy uruchamiali build ze sprawdzeniem tylko wtedy, gdy chcemy zweryfikować aplikację raz na kilka dni lub w określonych momentach sprintu, albo po dodaniu nowych zależności. Oczywiście nic nie stoi na przeszkodzie aby uruchamiać taki build codziennie i zawsze gdy chcemy sprawdzić nową paczkę z aplikacją – spowoduje to jednak, że od czasu do czasu build będzie dłuższy o kilka do kilkunastu minut.
Dla bojących się, że OWASP DC zacznie zabijać ich projekty bez powodu (np. w wyniku negatywnego sprawdzenia w bazach podatności), śpieszę z informacją, że DC pełni tylko rolę markera i nie wpływa na powodzenie kompilacji kodu i kolejnych kroków (chyba, że skorzystamy z innych mechanizmów narzędzia budującego, które po takim sprawdzeniu mają unieważnić paczkę albo nie dopuścić do jej stworzenia). Niemniej jednak – jeśli DC zwróci problem to i tak trzeba się pochylić nad jego szczegółami, zgodnie z tym co opisałem powyżej.
Na maszynie, na której wykonywany jest proces sprawdzenia musimy mieć dostęp do zewnętrznych zasobów internetu, w niektórych projektach może być problem z dostępem do nich np. ze względu na ograniczenia sieci w firmie np. w bankowości – upewnij się, że nie będzie z tym problemu.
W tym tutorialu opiszę przykład użycia OWASP DC w oparciu o przetestowanie projektu napisanego w Javie. Pracę z DC należy zacząć od konfiguracji pliku pom.xml
Dodajemy w sekcji build następujący wpis:
<build> <plugins> <plugin> <groupId>org.owasp</groupId> <artifactId>dependency-check-maven</artifactId> <version>5.3.2</version> <executions> <execution> <goals> <goal>check</goal> </goals> </execution> </executions> </plugin> </plugins> </build>
Jest to najprostsza konfiguracja projektu. Aby wygenerować raport należy uruchomić build narzędziem maven poleceniem mvn verify lub mvn site.
W powyższej konfiguracji wykonywany będzie update bazy podatności na maszynie (jeśli nie jest aktualna) oraz sprawdzenie projektu. Jeśli chcemy wykonywać tylko aktualizację bazy bez sprawdzania zależności (co może być przydatne w momencie gdy chcemy mieć osobny Job CI/CD który będzie automatycznie aktualizować bazę np. w nocy, dzięki czemu budowanie aplikacji w ciągu dnia nie będzie spowalniane przez update bazy danych podatności) wpis będzie wyglądać tak:
<build> <plugins> <plugin> <groupId>org.owasp</groupId> <artifactId>dependency-check-maven</artifactId> <version>5.3.2</version> <executions> <execution> <goals> <goal>update-only</goal> </goals> </execution> </executions> </plugin> </plugins> </build>
Następnie po uruchomieniu budowania wtyczka uruchomi się, a w logach pojawią się następujące wpisy:
Dokument zawierający logi jest dość długi, ten krok zajmuje od kilku sekund do kilkunastu minut (ma na to wpływ również przepustowość łącza internetowego).
Po zakończeniu procesowania jeśli zostały znalezione jakiekolwiek nieprawidłowości zostanie to zapisane w logach:
Przypominam, że projekt niemający dziś podatności, nie oznacza, że przy kolejnych sprawdzeniach nie pojawią się nowe problemy.
Oczywiście informacja w logach nie jest jedynym wynikiem. Wśród skompilowanych plików w katalogu target pojawić powinien się plik z raportem o nazwie dependency-check-report.html
Raport składa się z kilku części. Na samej górze jest opisana metryczkę sprawdzenia, sygnaturę i datę pobrania bazy podatności, ilość sprawdzonych bibliotek oraz stwierdzonych podatności. Ważne jest również to, że sprawdzane jest całe drzewo zależności projektu, a zatem także biblioteki, które są używane w podłączonych projektach są sprawdzane.
Kolejną już bardzo szczegółową częścią raportu jest opis podatnych bibliotek i znalezionych błędów:
Ta część raportu jest najważniejsza z punktu widzenia programistów i managementu – zawarte są tutaj informacje o sposobie reprodukcji podatności, dokładnym miejscu ich występowania (z dokładnością do metod), są też odnośniki do zewnętrznych zasobów opisujących znalezione problemy.
Teraz należy wykonać najbardziej krytyczną część całego procesu – trzeba zweryfikować znalezione problemy. W jaki sposób zrobić to najlepiej?
Na początek można przeanalizować, które z podatnych metod wykorzystujemy w naszej aplikacji wprost oraz spróbować zasymulować atak z wykorzystaniem takiej luki – w zależności od ich specyfikacji będzie to np. jakiś ciąg znaków, specyficzny payload w formie pliku, złośliwy kod HTML. W czasie takiego sprawdzenia może okazać się, że podatność faktycznie nas dotyka – wtedy należy rozważyć aktualizację bibliotek lub samodzielne naprawienie błędu (najczęściej w przypadku braku wypuszczenia łatki bezpieczeństwa ze strony twórców biblioteki) już w swojej aplikacji np. wprowadzając dodatkową walidację czy nadpisując używane metody czy klasy z użyciem wzorców projektowych np. fasady albo proxy.
Może się też okazać, że problem znajduje się w metodzie ukrytej w zależności używanej zależności :) – analiza będzie przebiegać podobnie – najpierw sprawdzamy czy używamy modułu z podatnością. Sprawdzenie może przebiegać analogicznie jak w przypadku bezpośredniego użycia podatnej metody.
Wyrok – czyli aktualizacja bibliotek, migracja do nowej wersji platformy czy cokolwiek innego powinny być podjęte dopiero po takowym sprawdzeniu. Sam fakt, że używasz podatnej biblioteki nie zawsze skutkuje błędami w Twoim oprogramowaniu.
Wygląda jak dużo pracy? Sama biblioteka, jak już pewnie zauważyliście nie jest skomplikowana, co jest zdecydowanie dużym plusem. Jest prosta i łatwa w użyciu, a przede wszystkim dająca szybki feedback oraz wyraźnie podnosząca świadomość bezpieczeństwa w projektach. Natomiast bezpieczeństwo – jak przy wykorzystaniu każdego innego narzędzia poprawi się tylko wtedy, kiedy wniesiemy dodatkowe nakłady pracy. Musimy przeznaczyć czas na analizę i weryfikację wyników – co niekiedy może być problemem, ale warto spróbować i wdrożyć takie rozwiązanie w projekcie choćby w formie krótkiego „proof of concept”, który może przekonać osoby decyzyjne lub kolegów z zespołu.
— Dariusz Kozon
Fajny art, jakby przetłumaczyć na angielski to mógłby robić za oficjalny tutorial na stronie OWASP :)
Polecam DependencyTrack od OWASP – działa dużo lepiej i daje mniej fp.
Ale obsługuje nieco inne przypadki. DependencyCheck używa się w fazie developmentu gdzie zależności podlegają ciągłym zmianom, a DependencyTrack w fazie używania, gdzie lista zależności jest statyczna.
Być może – niemniej jednak, patrząc na sposób rozwoju oprogramowania, nie jestem w stanie zwykle wyróżnić fazy developmentu i używania :) jeśli na etapie pipeline’a CICD będzie generacja pliku BOM (np. za pomocą pluginu do generacji CycloneDX, https://github.com/CycloneDX/cyclonedx-maven-plugin), to DependencyTrack z powodzeniem może być używany jako element CICD. Z mojego doświadczenia, DependencyCheck nie zawsze dobrze dopasowuje CVE do zależności – robi tam różne sztuczki, żeby dopasować artefakty po nazwie. Oczywiście dzięki temu może znaleźć to, czego BOM nie pokrywa, ale jednocześnie wymaga dodatkowej, bardzo żmudnej pracy przy raporcie.
Tak czy inaczej – artykuł na wielki plus! Zależności to temat, na który dopiero ostatnio zaczęto zwracać uwagę. A praktyka pokazuje, że podatności w nich (np. w sławnych Strusach) mocno uderzyły w niektórych…
Dzięki, z chęcią przetestuje DependencyTrack