O 123% więcej zgłoszonych CVE dziennie w 2026 niż przed rokiem.

Zależności

Czym jest zależność przechodnia?

Zależność przechodnia to pakiet, którego Państwa oprogramowanie używa, ponieważ potrzebuje go inny pakiet. Nigdy go Państwo nie zadeklarowali, ale znajduje się w tym, co Państwo dostarczają, z własnymi podatnościami i licencją. Oto, jak je zobaczyć, naprawić i udowodnić, które z nich trafiły do każdego wydania.

Zaktualizowano

A vulnerable transitive dependency and its fix path An app declares two direct dependencies, express and hbs. Express brings in body-parser and send, which bring in raw-body and mime-types. Hbs brings in handlebars, which is vulnerable. The path from the app through hbs to handlebars is highlighted: upgrade hbs, or override the handlebars version. your project direct transitive, depth 1 depth 2 my-app express hbs body-parser send handlebars vulnerable, required by hbs raw-body mime-types Fix path: upgrade hbs, or override the handlebars version

Zależności bezpośrednie i przechodnie

Zależność bezpośrednia to ta, którą Państwo deklarują w manifeście. Zależność przechodnia to ta, którą deklarują Państwa zależności, a potem ich zależności, tak głęboko, jak sięga drzewo. Menedżer pakietów rozwiązuje całe drzewo podczas instalacji i zwykle zapisuje wynik w lockfile.

Weźmy aplikację, która deklaruje jeden pakiet, express. Polecenie npm ls --all pokazuje, co przynosi ze sobą ten jeden wiersz:

my-app
└─┬ express            ← bezpośrednia: zadeklarowana przez Państwa
  ├─┬ body-parser      ← przechodnia, poziom 1
  │ └── raw-body       ← przechodnia, poziom 2
  ├── cookie           ← przechodnia, poziom 1
  └─┬ send             ← przechodnia, poziom 1
    └── mime-types     ← przechodnia, poziom 2

Prawdziwe drzewo jest dłuższe. Większość pakietów w typowej aplikacji trafia do niej właśnie w ten sposób, co oznacza, że większość dostarczanego przez Państwa kodu wybrał menedżer pakietów, a nie Państwo.

Zależność bezpośrednia Zależność przechodnia
Kto ją wybrał Państwa zespół, w manifeście Menedżer pakietów, na podstawie manifestów Państwa zależności
Gdzie jest wymieniona W manifeście i lockfile W lockfile, jeśli istnieje
Kto kontroluje wersję Państwo Zakres wersji pakietu nadrzędnego, chyba że go Państwo nadpiszą
Jak naprawić podatność Zaktualizować ją Zaktualizować pakiet nadrzędny lub nadpisać wersję

Dlaczego zależności przechodnie są ważne

Niosą te same ryzyka co zależności bezpośrednie, przy mniejszej widoczności i mniejszej kontroli.

  • Podatności. Gdy ujawniono Log4Shell, zero-day w log4j, zespół Open Source Insights firmy Google znalazł 35 863 artefakty w Maven Central zależne od podatnego kodu log4j. Około 7000 zależało od niego bezpośrednio. Większość pobierała go jako zależność przechodnią, a wielu nie dało się naprawić, dopóki poprawki nie wydał najpierw pakiet pośredni.
  • Ataki na łańcuch dostaw. Tylna furtka w xz utils (CVE-2024-3094) dotarła do OpenSSH, choć OpenSSH nie zależy od xz. Kilka dystrybucji Linuksa łata OpenSSH, aby obsługiwał powiadomienia systemd, a libsystemd zależy od liblzma, biblioteki dostarczanej przez xz.
  • Licencje. Każdy pakiet przechodni ma własną licencję. Licencja copyleft trzy poziomy niżej wiąże tak samo jak ta, którą dodali Państwo sami.
  • Zmiany niekompatybilne. Pakiet nadrzędny akceptujący zakres wersji wpuszcza nowe wydanie przechodnie przy kolejnej czystej instalacji, nawet jeśli w Państwa manifeście nic się nie zmieniło.

Jak wyświetlić zależności przechodnie

Każdy główny menedżer pakietów potrafi wypisać rozwiązane drzewo:

Ekosystem Polecenie
npmnpm ls --all
pnpmpnpm list --depth Infinity
Python (uv)uv tree
Python (pip)pipdeptree
Gogo mod graph
Rustcargo tree
Mavenmvn dependency:tree
Gradlegradle dependencies

Aby dowiedzieć się, dlaczego dany pakiet się tam znajduje, należy zapytać o prowadzącą do niego ścieżkę: npm explain <package>, pnpm why, yarn why lub cargo tree -i <crate>. Pracę ze ścieżkami, a nie tylko ich wypisywanie, opisuje strona grafy zależności.

Jak naprawić podatną zależność przechodnią

  1. Zaktualizować pakiet nadrzędny. Należy znaleźć zależność bezpośrednią, która pobiera pakiet, i przejść na wydanie wymagające wersji z poprawką. To najczystsza naprawa, ponieważ opiekunowie pakietu nadrzędnego ją przetestowali.
  2. Odświeżyć lockfile. Jeśli zakres wersji pakietu nadrzędnego już dopuszcza wersję z poprawką, wystarczy zaktualizować wpis w lockfile, na przykład przez cargo update -p <crate> lub ponowne npm update.
  3. Nadpisać wersję. Jeśli pakiet nadrzędny nie wydał poprawki, należy samodzielnie wymusić wersję: overrides w npm i pnpm, resolutions w Yarn, plik ograniczeń w pip lub wyższe wymaganie w go.mod. Trzeba to przetestować, ponieważ pakiet nadrzędny nigdy nie został wydany z tą wersją.
  4. Zastąpić lub usunąć pakiet nadrzędny. Jeśli żadna z tych metod nie zadziała, zależność wprowadzająca pakiet może nie być już warta zachowania.

Niektóre narzędzia analizy składu oprogramowania dodają analizę osiągalności, która sprawdza, czy Państwa kod w ogóle może wywołać podatną funkcję, aby zdecydować, którą z tych napraw wykonać najpierw. Dostępne opcje przedstawia porównanie narzędzi SCA.

Dlaczego lockfile to nie wszystko

Większość narzędzi buduje swój obraz zależności przechodnich na podstawie lockfile. Działa to, gdy lockfile istnieje, jest aktualny i stanowi jedyne źródło instalacji w buildzie. W CI często tak nie jest:

  • Brak lockfile. requirements.txt z zakresami wersji lub projekt, który nigdy nie dodał lockfile do repozytorium, jest rozwiązywany od nowa przy każdym buildzie, więc wersje przechodnie mogą się zmieniać między buildami.
  • Cache. Cache CI przywracają pakiety z wcześniejszych uruchomień zamiast je pobierać, a ich zawartość nie zawsze odpowiada temu, co podaje bieżący lockfile. Zob. co ukrywa cache GitHub Actions.
  • Narzędzia buildu. Lintery, kompilatory, generatory kodu i kroki konfiguracyjne wnoszą do buildu własne drzewa zależności. Nie ma ich w manifeście aplikacji, ale działają z dostępem do Państwa kodu źródłowego i sekretów.
  • Skrypty instalacyjne i pobrania. Skrypt instalacyjny pakietu może pobrać dodatkowy kod, a krok buildu może bezpośrednio pobrać plik binarny. Żadne z nich nie zostawia wpisu w lockfile.

Jedyny kompletny zapis tego, które zależności przechodnie trafiły do wydania, to zapis wykonany podczas budowania tego wydania. Różnicę między rejestrowaniem buildu a późniejszym skanowaniem jego plików wyjaśnia strona SBOM-y z czasu buildu.

Zależności przechodnie a CRA

Unijny Cyber Resilience Act wymaga od producentów sporządzenia SBOM obejmującego „co najmniej zależności najwyższego poziomu produktów” (załącznik I, część II pkt 1). Zależności przechodnie nie są wymienione, więc prawne minimum jest niższe, niż sugeruje wiele poradników. CRA wymaga jednak także identyfikowania i obsługi podatności w komponentach zawartych w Państwa produkcie, a podatny pakiet przechodni jest jednym z nich. SBOM kończący się na pierwszym poziomie pozostawia większość drzewa zależności poza tym procesem. Szczegóły opisuje strona wymagania CRA dotyczące SBOM.

Jak CRACI śledzi zależności przechodnie

CRACI to runner GitHub Actions, który rejestruje build, zamiast go skanować. Podczas działania każdego zadania proxy rozpoznające pakiety rejestruje każdy pobrany przez nie pakiet, na każdym poziomie drzewa, łącznie z pakietami przywróconymi z cache CI. Daje to pełniejszy obraz używanych zależności niż narzędzia oparte na skanerach.

  • Każdy poziom, uczciwie opisany. SBOM każdego zadania ma stan kompletności, więc wiedzą Państwo, kiedy rejestracja nie mogła zobaczyć wszystkiego.
  • Widoczne drzewo. Graf zależności pokazuje warstwy zależności SBOM w kilku widokach.
  • Eksporty, które je zawierają. Eksporty CycloneDX i SPDX zawierają zależności przechodnie, każdą z deklarowaną licencją.
  • Których buildów to dotyczyło. Gdy pojawia się nowa podatność, historia buildów pokazuje, które wcześniejsze buildy zawierały podatny pakiet, bezpośredni lub przechodni, dzięki czemu znają Państwo okres, w którym go dostarczano (zob. czy dotyczy nas dana CVE?). Historia zależy od Państwa okresu retencji, domyślnie 180 dni.
  • Bramki polityk. Build zawierający określoną CVE można zablokować przed wydaniem.

CRACI nie wykonuje analizy osiągalności. Jeśli muszą Państwo wiedzieć, czy Państwa kod wywołuje podatną funkcję, należy połączyć go z narzędziem SCA, które to robi. Zob. generowanie SBOM w CRACI lub proszę umówić demo, aby zarejestrować jeden z Państwa buildów.

Zależności przechodnie: najczęściej zadawane pytania

Czym jest zależność przechodnia?

Zależność przechodnia to pakiet, którego Państwa oprogramowanie używa, ponieważ potrzebuje go inny pakiet. Jeśli Państwa aplikacja zależy od biblioteki A, a A zależy od biblioteki B, to B jest przechodnią, czyli pośrednią, zależnością Państwa aplikacji. Nigdy jej Państwo nie zadeklarowali, ale jest dostarczana z Państwa oprogramowaniem.

Czym zależność bezpośrednia różni się od przechodniej?

Zależność bezpośrednia to ta, którą Państwo deklarują w manifeście, takim jak package.json, pyproject.toml lub go.mod. Zależność przechodnia to ta, którą deklarują Państwa zależności bezpośrednie, na dowolnym poziomie. Zależności bezpośrednie wybierają Państwo; przechodnie wybiera menedżer pakietów podczas rozwiązywania drzewa.

Czy zależność przejściowa to to samo co zależność przechodnia?

W praktyce tak. „Zależność przejściowa” to częsta pomyłka zamiast „zależność przechodnia”. Poprawny termin to przechodnia, od relacji przechodniej: jeśli A zależy od B, a B zależy od C, to A zależy od C.

Jak naprawić podatność w zależności przechodniej?

Najpierw należy zaktualizować zależność bezpośrednią, która ją pobiera, jeśli istnieje wydanie z wersją zawierającą poprawkę. Jeśli nie, trzeba wymusić tę wersję mechanizmem nadpisywania menedżera pakietów, takim jak overrides w npm, resolutions w Yarn lub plik ograniczeń pip, i sprawdzić, czy pakiet nadrzędny nadal z nią działa.

Jak wyświetlić wszystkie zależności przechodnie?

Każdy menedżer pakietów potrafi wypisać rozwiązane drzewo: npm ls --all, pnpm list --depth Infinity, uv tree lub pipdeptree, go mod graph, cargo tree, mvn dependency:tree lub gradle dependencies. Aby wiedzieć, co faktycznie zainstalował build produkcyjny, należy zarejestrować sam build.

Czy unijny Cyber Resilience Act wymaga zależności przechodnich w SBOM?

Rozporządzenie wyznacza minimum: „co najmniej zależności najwyższego poziomu produktów” (załącznik I, część II pkt 1). Zależności przechodnie nie są wymienione, ale podatny pakiet przechodni nadal znajduje się w Państwa produkcie, a CRA wymaga obsługi podatności w dostarczanych komponentach.

Każda zależność pobrana przez Państwa build

Proszę uruchomić jeden workflow GitHub Actions na CRACI i otrzymać zarejestrowany SBOM każdego pobranego pakietu, na każdym poziomie drzewa.

Umów demo