W rozwoju oprogramowania jesteśmy zależni zarówno od własnych, jak i zewnętrznych komponentów lub artefaktów. Elastyczne zarządzanie zależnościami jest niezbędne dla nowoczesnego oprogramowania. Menedżery pakietów, takie jak NPM, Maven, pypeć or NuGeta są często używane do określania zależności oprogramowania. Narzędzia te zostały zaprojektowane z myślą o wygodzie i łatwości użytkowania, a nie bezpieczeństwie.
Problem
Problem polega na tym, że elastyczność i łatwość obsługi dla programistów sprawiają, że złoczyńcy, którzy postrzegają zależności oprogramowania jako coś nieodparcie kuszącego dla ich biznesu, podchodzą do tego z przymrużeniem oka. W rezultacie złoczyńcy podążali wszystkimi możliwymi ścieżkami ataku przedstawionymi tutaj. Źródło: „Backstabber's Knife Collection: A Review of Open Source Software Supply Chain Attacks”
W tym poście skupimy się na stosowaniu deklaracji wersji otwartych, w tym sensie, że pobrana wersja nie jest stała, lecz musi należeć do określonego zakresu. W momencie kompilacji menedżer pakietów wybiera i pobiera/instaluje najwyższą istniejącą wersję zgodną z określonym zakresem wersji.
Zilustrujmy otwarte deklaracje w deklaracjach zależności dla różnych menedżerów pakietów:
- NPM: pakiet.json
{
...
„zależności”: {
...
„akceptuje”: „>=1.3.8”,
„lodash”: „~4.16.0”,
...
},
...
}
Zainstalowana zostanie największa istniejąca wersja pakietu accepts (nie niższa niż 1.3.8), a także największa aktualizacja „łatki” dla lodash z serii 4.16.x.
- Maven: pom.xml
...
...
commons-io
commons-io
UWOLNIENIE
...
...
Ostatnia dostępna wersja dla commons-io (plik jar) zostanie dodana jako zależność.
- Pypeć: konfiguracja.py
...
organizować coś(
...
install_requires=['peppercorn', 'launchpadlib'],
...
)
...
Takie otwarte schematy wersji mają swoje dobre i złe strony. Dobrą jest to, że nowsze wersje zazwyczaj Zawierają ulepszenia funkcjonalne i jakościowe, poprawki błędów i poprawki zabezpieczeń, które są automatycznie aktualizowane. Należy pamiętać, że w przypadku większości rzeczywistych projektów poprawki nie są przenoszone do poprzednich, pomniejszych wydań, z wyjątkiem poważnych luk w zabezpieczeniach. Wersje otwarte nadają się również do użytku w bibliotekach, aby zmniejszyć liczbę wersji, które trzeba zainstalować po rozwiązaniu wszystkich zależności.
Ale otwarte zakresy wersji mają też swoją złą stronę. Nie wiadomo dokładnie, które wersje zostaną zainstalowane w momencie kompilacji, a kompilacje nie są powtarzalne. Jest też ciemny Popieraj otwarte wersje. Jeśli atakującemu uda się opublikować złośliwy komponent w publicznym repozytorium w wysokiej wersji kompatybilnej z Twoim otwartym zakresem, Twoja kolejna kompilacja będzie zawierać złośliwy komponent, a być może nawet uruchomi złośliwe oprogramowanie w skryptach instalacyjnych, które mogą być uruchamiane automatycznie. Ukrywanie ładunku ataku to prawdziwa sztuka.
Jest to znane jako Brak przypinania wersji kwestia.
Hakerzy zawsze próbują umieszczać złośliwe wersje popularnych pakietów open source. Mogą uzyskać dostęp do kluczy do repozytoriów pakietów poprzez tajny wyciek; często stosują socjotechnikę lub ukrywają zagnieżdżoną złośliwą zależność w pozornie użytecznym pull request. Nawet kilku autorów pewnego dnia dochodzi do wniosku, że świat nie jest sprawiedliwy i gryzie swoich klientów oprogramowanie protestacyjne w ich własnych opakowaniach!
Wyobraź sobie, że pracujesz w organizacji, która wykorzystuje zarówno wewnętrzne komponenty, jak i te oparte na oprogramowaniu typu open source.
Jeśli osoba atakująca zna nazwy takich wewnętrznych komponentów, może opublikować komponent o tej samej nazwie w publicznym repozytorium. Wiele menedżerów pakietów najpierw pobiera publiczne komponenty, a jeśli wersja jest poprawnie wybrana i wersja w zadeklarowanej zależności jest otwarta, bum! Ten problem nazywa się… Zamieszanie związane z zależnością.
Pokażmy przykład. Załóżmy, że w naszym projekcie NPM mamy zależność od prywatnego komponentu:
- NPM: pakiet.json
{
„nazwa”: „mój-projekt”,
...
„zależności”: {...
„mój-prywatny-zależność”: „>=1.0.0”,...
}
...
}
Atakujący może utworzyć wyższą wersję my-private-dep (np. 99.0.0) i opublikować ją w publicznym repozytorium npm, używając własnego fałszywego konta (atakujący nie musi nic robić w mojej organizacji). Menedżer pakietów NPM zainstaluje szkodliwą zależność, często z katastrofalnymi skutkami.
rozwiązanie
Aby uniknąć tych problemów w procesie tworzenia oprogramowania, powinniśmy przestrzegać ścisłych norm dotyczących deklarowania wersji komponentów, które zależą od używanej technologii. Ważne jest, aby konkretna wersja pakietu, po opublikowaniu w repozytorium, była niezmienna (aby uniknąć uszkodzenia zależności, nie tylko ze względów bezpieczeństwa).
Ogólna idea polega na skupieniu się (sosna) wersje, zawsze sprawdzając, czy stałe wersje komponentów (wliczając WSZYSTKIE zależności przechodnie) są wolne od złośliwego oprogramowania, co jest możliwe dzięki pliki blokujące które oferuje wiele menedżerów pakietów. Zobaczmy, jak działa przypinanie wersji w różnych menedżerach pakietów. Istnieje delikatny kompromis między częste aktualizacje wersji w celu naprawy znanych luk w zabezpieczeniach i wersja przypinana aby uniknąć niedeterministycznych kompilacji i potencjalnych ataków na łańcuch dostaw.
- NPM:
Menedżery pakietów npm lub yarn używają różnych plików blokady (odpowiednio npm-shrinkwrap.json / package-lock.json lub yarn.lock), które zawierają listę poprawionych wersji dla wszystkich zależności, bezpośrednich i pośrednich. Pliki blokady powinny być objęte kontrolą wersji, w przeciwnym razie inni deweloperzy/kompilujący węzły mogą zakończyć działanie z innymi wersjami. Unikaj instalacji npm, chyba że w fazie rozwoju musisz zaktualizować zależności (np. w celu zainstalowania poprawek bezpieczeństwa). Ogólnie rzecz biorąc, używaj bardziej deterministycznego polecenia npm ci (Clean Install), dzięki czemu menedżer pakietów użyje pliku blokady lub zakończy działanie z błędem, jeśli plik blokady nie będzie pasował do pliku package.json. Jeśli wymienione wersje zostały sprawdzone pod kątem złośliwego oprogramowania, plik blokady gwarantuje, że nic złego nie wydarzy się podczas kompilacji.W przypadku komponentów wewnętrznych zaleca się utworzenie Zakres NPM zarządzane przez organizację (np. @myorg) i używać tego zakresu w zależności (np. @myorg/my-private-dep), który może mieć tylko prywatną widoczność. To blokuje pomieszanie zależności ataków, ponieważ tylko członkowie organizacji mający dostęp do zapisu mogą publikować pakiety w ramach takiego zakresu.
- NPM:
- Maven:
Maven/Gradle nie mają plików blokady (ale zobacz ten artykuł na StackOverflow).Zakresy wersji nie są używane w Maven/Gradle tak często, jak w innych ekosystemach. Po prostu unikaj zakresy wersji i NAJNOWSZE lub WYDANE meta-wersje. Należy również sprawdzić wersje pośrednie. Wersje wtyczki Maven jest świetnym narzędziem do kontroli wersji.
Należy pamiętać, że Maven zawsze uwzględniał koncepcję zakresu organizacji (część groupId zależności), a pomyłki dotyczące zależności nie wydają się w ogóle stanowić problemu w tym ekosystemie.
- Maven:
- Pypeć:
W Pythonie istnieją różne narzędzia do obsługi plików blokad:- pipenv, który generuje plik blokady Pipfile.lock.
- poezja, który generuje poetry.lock.
- zamrożenie pip, polecenie generujące plik requirements.txt, który działa jak plik blokady. Sprawdź, czy wszystkie zależności korzystają z wersji stałych za pomocą operatora ==. Następnie polecenie pip install -r requirements.txt korzysta ze stałych zależności.
- Pypeć:
Przypomnij, że powyższe pliki blokady powinny podlegać kontroli wersji i że wybrane polecenie kompilacji powinno używać pliku blokady.
Zwykłe repozytorium pakietów używane z pip (PyPI) nie ma zakresów nazewnictwa i jest podatne na ataki polegające na pomyłce zależności. Unikanie pomyłek w zależnościach w ekosystemie Pythona nie jest łatwe i niektórzy autorzy zalecają korzystanie z wewnętrznego repozytorium, które będzie działać jako serwer proxy dla publicznych zależności pobranych z PyPI, ale najpierw należy pobrać prywatne zależności z wewnętrznego repozytorium (-index-url powinno wskazywać na wewnętrzne repozytorium, a nie PyPI, a –extra-index-url należy usunąć).
Kilka prawdziwych ataków
Atak Getcookies:Aktor dustin87 dodał pośrednią zależność do popularnego pakietu npm mailparser do złośliwego pakietu z tylnym wejściem RCE (gCOMMANDhDATAi):
JSON.stringify(req.headers).replace(/g([a-f0-9]{4})h((?:[a-f0-9]{2})+)i/gi, (o, p, v) => {})Pomimo wycofania (brak recenzji!), Mailparser nadal otrzymywał około 64 000 pobrań tygodniowo. Był to przypadek ataku niemalże chybionego, ponieważ RCE nie był w rzeczywistości używany.ciswyd.
NPM opublikowane ten post ze szczegółami dotyczącymi ataku getcookies.
Zamieszanie związane z zależnością:
Alex Birsan odkrył w 2021 roku problem pomieszania zależności i opublikował post zatytułowany „Jak włamałem się do Apple, Microsoftu i dziesiątek innych firm".
Pamiętaj, że w przypadku npm zakres organizacji, taki jak @myorg, powinien być zarezerwowany, a pakiety wewnętrzne powinny zostać zmodyfikowane, aby wykorzystywały ten zakres.
W przypadku pip, publiczny rejestr PyPI nie posiada zakresów/przestrzeni nazw. Każdy prywatny pakiet może mieć publiczny squat o tej samej nazwie co pakiet wewnętrzny, ale pusty i potencjalnie generujący błąd podczas użycia, co umożliwia identyfikację w przypadku przypadkowego pobrania.
Węzeł-ipc:
Właściciel pakietu, gdy wybuchła wojna rosyjsko-ukraińska, wstrzyknął złośliwy kod usuwający losowe pliki po zainstalowaniu na hostach rosyjskich i białoruskich. Plik ssl-geospec.js dokonywał takiego rozróżnienia geograficznego:
Co ciekawe, inne pakiety korzystały z otwartych wersji dla zależności node-ipc, jak np. popularny framework Vue.js, a jego opiekunowie otrzymali pilny apel aby przypiąć zależność node-ipc do bezpiecznej wersji.
Ten post zawiera więcej szczegółów na ten sabotaż, który idzie o krok dalej od innych Protestware problemy.
Uwagi końcowe
Otwarte wersje powinny nigdy być stosowane w skonsolidowanych projektach oprogramowania. Uniemożliwiają one powtarzanie kompilacji, a atakujący mogą je wykorzystać i wstrzyknąć złośliwe oprogramowanie poprzez ataki na drzewa zależności, takie jak wspomniane wcześniej pomieszanie zależności.
Błędne konfiguracje, takie jak otwarte wersje, brak przypinania wersji lub nieograniczone wewnętrzne komponenty Należy tego unikać. Przede wszystkim należy wykrywać takie problemy, a nawet blokować kompilację, gdy zostaną wykryte, i opracować standardowy protokół postępowania.
Automatyczne wykrywanie błędów i błędnych konfiguracji w zależnościach, zgłaszanie podejrzanych zależności, które mogą być podatne na określone ataki na łańcuch dostaw, takie jak pomieszanie zależności, wszystko z praktycznymi narzędziami naprawczymi, jest jednym z głównych celów Platforma Xygeni.
| Aby przeczytać więcej |
| Ohm M., Plate H., Sykosch A., Meier M.: „Kolekcja noży Backstabber: Przegląd ataków na łańcuch dostaw oprogramowania open source”. DIMVA 2020. Notatki z wykładów z informatyki, tom 12223. Springer – 2020 (źródło rysunku drzewa ataków zależności). |
| @adam-npm: „Zgłoszono złośliwy moduł: getcookies„. Blog npm (archiwum) – 2 maja 2018 r. |
| Alex Birsan: „Jak włamałem się do Apple, Microsoftu i dziesiątek innych firmMedium – 9 lutego 2021 r. |
| Ax Sharma: „WIELKI sabotaż: Słynny pakiet npm usuwa pliki w proteście przeciwko wojnie na Ukrainie” BleepingComputer – 17 marca 2022 |







