10 zasad bezpiecznych zależności w Twojej aplikacji
Dziś opowiem Ci o tym jak pilnować 10 zasad bezpiecznych zależności tworząc nowe systemy.
Każda biblioteka dołączona do naszego systemu to potencjalnie niebezpieczny element, którego nie znamy, ale pozwalamy mu się uruchomić wewnątrz naszej aplikacji.
Spójrzmy na analogię. Masz samochód. Czy dałbyś/dałabyś go do prowadzenia każdej osobie? Rodzinie pewnie tak (może z pewnymi wyjątkami ;)), kilku przyjaciołom może też, ale czy gdyby ktoś nieznany na ulicy zapytał Cię o to? Sam byłbym wtedy bardzo niechętny.
Tak samo jest z bibliotekami — żeby je dołączyć do naszego systemu, powinniśmy upewnić się, że możemy im zaufać. Jednak jak to zrobić?
10 zasad bezpiecznych zależności
Jak zadbać o to, żeby używać tylko bezpiecznych bibliotek?
Za każdym razem, gdy dodajemy nową bibliotekę do naszego systemu, powinniśmy zwrócić uwagę na kilka ważnych rzeczy:
Zaufane źródło
Pobieraj biblioteki tylko z oficjalnych, zaufanych źródeł.
Nigdy nie pobierajmy bibliotek z losowych miejsc w sieci. Dodanie ich do systemu to jak proszenie nieznajomego, żeby popilnował Ci domu, gdy wyjedziesz na wakacje.
Zawsze powinniśmy pobierać biblioteki z oficjalnych rejestrów jak npm czy NuGet. W ten sposób też dużo łatwiej. Jak już musimy z jakichkolwiek powodów pobrać bibliotekę i osadzić ją w aplikacji, przynajmniej pobierzmy ją z oficjalnego źródła jak na przykład strona twórcy lub rejestr (np. npm).
Zgodna licencja
Zanim postanowimy skorzystać z danej biblioteki, musimy upewnić się, że możemy ją wykorzystać w projekcie. Powinniśmy głównie zwrócić uwagę na to, co jest zabronione w danej licencji. Na przykład na zabronione komercyjne użycie lub wymuszenie opublikowania źródeł aplikacji. Na szczęście, nie musisz czytać dokładnie każdej licencji. Wystarczy, że sprawdzisz ją na stronie https://www.tldrlegal.com – to świetne źródło skróconej wiedzy na temat różnych licencji.
Obecność podatności
Koniecznie też trzeba zweryfikować, czy biblioteka ma znane podatności. Można to sprawdzić w publicznych rejestrach takich jak Snyk DB (https://security.snyk.io/). Obecność znanych podatności jest dla nas sygnałem, że biblioteka nie jest bezpieczna, więc przed użyciem jej musimy świadomie zaakceptować ryzyko z tym związane (lub oczywiście po zapoznaniu się z ryzykiem podjąć decyzję o tym, że z niej nie skorzystamy). Ponadto, w takich rejestrach każda podatność posiada ocenę istotności, która pomoże nam ocenić ryzyko związane z dołączeniem jej do systemu.
Opisałem to szerzej w [???]
Szansa na poprawki
Nawet gdy biblioteka nie ma żadnych znanych obecnie podatności, to jest szansa, że w przyszłości zostaną one znalezione i zgłoszone. Warto więc dodatkowo zweryfikować, jaka jest szansa, że gdy takie podatności zostaną upublicznione, biblioteka będzie szybko naprawiona. Można to rozpoznać po tym jak szybko są robione poprawki dla poprzednich błędów bezpieczeństwa lub w ogóle dla błędów w działaniu.
Dojrzałość biblioteki
Również warto zweryfikować to czy biblioteka w dojrzały sposób podchodzi do zadbania o własne bezpieczeństwo. Narzędzie w stylu OpenSSF ScoreCard (https://securityscorecards.dev/viewer/?uri=github.com/ossf/scorecard) pozwoli nam sprawdzić, czy projekt ma skonfigurowane automatyczne skanowanie bezpieczeństwa, czy branche są zabezpieczone przed niekontrolowanymi zmianami, a także sprawdzi, czy w bibliotece nie ma żadnych niepokojących plików lub skryptów.
Opisałem to szerzej w [???]
Regularne aktualizowanie
Każda biblioteka, z której korzystamy w systemie, powinna być regularnie aktualizowana. Różnica pomiędzy wersją, z której korzystamy w systemie, a najnowszą dostępną wersją danej biblioteki powinna być jak najmniejsza. Dzięki temu łatwiej nam będzie zaktualizować ją w momencie wykrycia jakichkolwiek problemów, a w szczególności krytycznej, podatności. Wtedy będzie nam zależało na czasie, więc warto zadbać o to, żeby naprawa problemów w przyszłości była jak najprostsza.
Monitorowanie bezpieczeństwa
Bezpieczeństwo naszych zależności powinno być weryfikowane nie tylko podczas dodawania biblioteki. Rzeczywiście, to świetny moment, ale stan bezpieczeństwa danego projektu może z czasem bardzo szybko się zmienić. Świetnym przykładem jest biblioteka log4j. Pewnie już nie raz obiła Ci się ta nazwa o uszy. Swego czasu była ona na ustach większości osób zajmujących się bezpieczeństwem. W grudniu 2021 roku odkryto w niej krytyczną podatność. Dotyczyła ona wszystkich wersji aż od 2014 roku. To oznacza, że przez 7 lat w bibliotece istniała krytyczna podatność, ale nikt tego wcześniej nie zgłosił. Dlatego tym bardziej ważne jest regularne monitorowanie stanu naszych zależności.
Izolowanie od ekosystemu
Gdy dołączamy nową bibliotekę, nie zawsze mamy 100% pewność co do jej bezpieczeństwa. W związku z tym czasem warto uruchamiać je w wyizolowanym środowisku. W przypadku bibliotek Python może to polegać na tym, że zostaną one użyte w osobnym środowisku wirtualnym (venv). Tego typu izolacją i zmniejszaniem potencjalnej przestrzeni ataku (w przypadku mniej zaufanych bibliotek) jest też korzystanie z mikroserwisów, a nawet z nanoserwisów. Podział systemu na odpowiednio małe kawałki pomoże zmniejszyć ryzyko, że ktoś w wyniku wykorzystania podatności, skompromituje całą naszą aplikację.
Kontrola integralności zależności
Mimo że nie jest to zalecane, nieraz musimy załączyć bibliotekę do naszego systemu bezpośrednio z zewnętrznej lokalizacji. Na przykład korzystając z usług Stripe, musimy pobrać plik stripe.js
z ich serwera. To dość oczywiste, jednak co by się stało gdybyśmy dołączyli do systemu bibliotekę hostowaną na zewnętrznym CDN, a ten CDN zostałby skompromitowany (czyli że ktoś przejąłby nad nim kontrolę). To oznacza, że atakujący mógłby zmodyfikować zawartość takiej biblioteki, dodając złośliwy kod. Ten złośliwy kod zostałby uruchomiony w naszej aplikacji, bez żadnej zmiany w samej aplikacji.
Dlatego też warto w takich przypadkach weryfikować hash (skrót) takiego pliku i sprawdzać, czy ten skrót nie zmienił się w pewnym czasie. To oznacza zmianę w kodzie biblioteki. Jednak musimy jeszcze zweryfikować, czy ta zmiana jest dla nas niebezpieczna.
Wiedza o tym, co jest w użyciu
Ostatnia zasada, jednak nie mniej ważna niż inne, to bycie doinformowanym. Powinniśmy być świadomi tego, z jakich bibliotek korzystamy i w jaki sposób dodajemy je do systemu. Dzięki temu będziemy w stanie szybciej i sprawniej reagować na zagrożenia, gdy zostaną one zidentyfikowane.
Te 10 zasad bezpiecznych zależności, choć nie zawsze łatwo je stosować, skutecznie obronią nas przed słabymi bibliotekami, które będziemy chcieli dodać do systemu.
Powodzenia w weryfikacji!