Vuonna 2026 raportoitiin päivässä 131% enemmän CVE:itä kuin edellisenä vuonna.

Riippuvuudet

Mikä on transitiivinen riippuvuus?

Transitiivinen riippuvuus on paketti, jota ohjelmistosi käyttää, koska jokin toinen paketti tarvitsee sitä. Et koskaan ilmoittanut sitä, mutta se on mukana siinä, mitä toimitat, omine haavoittuvuuksineen ja lisensseineen. Näin näet ne, korjaat ne ja osoitat, mitkä niistä päätyivät kuhunkin julkaisuun.

Päivitetty

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

Suorat ja transitiiviset riippuvuudet

Suora riippuvuus on riippuvuus, jonka ilmoitat manifestissasi. Transitiivinen riippuvuus on riippuvuus, jonka riippuvuutesi ilmoittavat, ja niiden riippuvuudet vuorostaan, niin syvälle kuin puu ulottuu. Paketinhallinta ratkaisee koko puun asennuksen yhteydessä ja tallentaa tuloksen yleensä lukitustiedostoon (lockfile).

Otetaan sovellus, joka ilmoittaa yhden paketin, express. Komento npm ls --all näyttää, mitä tuo yksi rivi tuo mukanaan:

my-app
└─┬ express            ← suora: sinä ilmoitit sen
  ├─┬ body-parser      ← transitiivinen, taso 1
  │ └── raw-body       ← transitiivinen, taso 2
  ├── cookie           ← transitiivinen, taso 1
  └─┬ send             ← transitiivinen, taso 1
    └── mime-types     ← transitiivinen, taso 2

Todellinen puu on pidempi. Suurin osa tyypillisen sovelluksen paketeista tulee tätä kautta, joten suurimman osan toimittamastasi koodista on valinnut paketinhallinta, et sinä.

Suora riippuvuus Transitiivinen riippuvuus
Kuka sen valitsi Tiimisi, manifestissa Paketinhallinta, riippuvuuksiesi manifestien perusteella
Missä se on listattu Manifestissa ja lukitustiedostossa Lukitustiedostossa, jos sellainen on
Kuka määrää version Sinä Yläpaketin versioväli, ellet ohita sitä
Miten haavoittuvuus korjataan Päivitä se Päivitä yläpaketti tai ohita versio

Miksi transitiivisilla riippuvuuksilla on väliä

Niissä on samat riskit kuin suorissa riippuvuuksissa, mutta näkyvyyttä ja hallintaa on vähemmän.

  • Haavoittuvuudet. Kun log4j:n nollapäivähaavoittuvuus Log4Shell julkistettiin, Googlen Open Source Insights -tiimi löysi 35 863 Maven Centralin artefaktia, jotka riippuivat haavoittuvasta log4j-koodista. Noin 7 000 riippui siitä suoraan. Suurin osa sai sen transitiivisena riippuvuutena, ja monia ei voitu korjata ennen kuin välissä oleva paketti oli ensin julkaissut korjauksen.
  • Toimitusketjuhyökkäykset. xz utilsin takaovi (CVE-2024-3094) ulottui OpenSSH:hon, vaikka OpenSSH ei riipu xz:sta. Useat Linux-jakelut paikkaavat OpenSSH:ta tukemaan systemd-ilmoituksia, ja libsystemd riippuu liblzmasta, xz:n tarjoamasta kirjastosta.
  • Lisenssit. Jokaisella transitiivisella paketilla on oma lisenssinsä. Kolmen tason syvyydessä oleva copyleft-lisenssi sitoo yhtä lailla kuin itse lisäämäsi.
  • Rikkovat muutokset. Yläpaketti, joka hyväksyy versiovälin, päästää uuden transitiivisen julkaisun sisään seuraavassa puhtaassa asennuksessa, vaikka manifestissasi ei olisi muuttunut mitään.

Miten listaat transitiiviset riippuvuutesi

Jokainen merkittävä paketinhallinta osaa tulostaa ratkaistun puun:

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

Jos haluat tietää, miksi yksittäinen paketti on mukana, kysy polkua siihen: npm explain <package>, pnpm why, yarn why tai cargo tree -i <crate>. Jos haluat käsitellä polkuja etkä vain tulostaa niitä, katso riippuvuusgraafit.

Miten korjaat haavoittuvan transitiivisen riippuvuuden

  1. Päivitä yläpaketti. Etsi suora riippuvuus, joka tuo paketin mukaan, ja siirry julkaisuun, joka vaatii korjatun version. Tämä on siistein korjaus, koska yläpaketin ylläpitäjät ovat testanneet sen.
  2. Päivitä lukitustiedosto. Jos yläpaketin versioväli jo sallii korjatun version, lukitustiedoston merkinnän päivittäminen riittää, esimerkiksi komennolla cargo update -p <crate> tai uudella npm update -ajolla.
  3. Ohita versio. Jos yläpaketti ei ole julkaissut korjausta, pakota versio itse: overrides npm:ssä ja pnpm:ssä, resolutions Yarnissa, constraints-tiedosto pipillä tai korkeampi vaatimus tiedostossa go.mod. Testaa se, koska yläpakettia ei ole koskaan julkaistu tätä versiota vasten.
  4. Korvaa tai poista yläpaketti. Jos kumpikaan ei toimi, paketin mukaan tuova riippuvuus ei ehkä ole enää säilyttämisen arvoinen.

Jotkin ohjelmistokoostumuksen analyysin (SCA) työkalut lisäävät reachability-analyysin, joka tarkistaa, voiko koodisi ylipäätään kutsua haavoittuvaa funktiota, ja päättävät sen perusteella, mikä näistä korjauksista tehdään ensin. Vaihtoehdot löytyvät sivulta SCA-työkalut vertailussa.

Miksi lukitustiedosto ei kerro kaikkea

Useimmat työkalut muodostavat kuvansa transitiivisista riippuvuuksista lukitustiedoston perusteella. Se toimii, kun lukitustiedosto on olemassa, ajan tasalla ja ainoa lähde, josta buildi asentaa. CI:ssä näin ei useinkaan ole:

  • Ei lukitustiedostoa. Versiovälejä sisältävä requirements.txt tai projekti, joka ei koskaan commitoinut lukitustiedostoaan, ratkaistaan uudelleen jokaisessa buildissa, joten transitiiviset versiot voivat vaihtua buildien välillä.
  • Välimuistit. CI-välimuistit palauttavat paketteja aiemmista ajoista sen sijaan, että hakisivat ne, eikä niiden sisältö aina vastaa nykyistä lukitustiedostoa. Katso mitä GitHub Actions -välimuisti piilottaa.
  • Build-työkalut. Linterit, kääntäjät, koodigeneraattorit ja asennusvaiheet tuovat buildiin omat riippuvuuspuunsa. Ne eivät ole sovelluksesi manifestissa, mutta ne ajetaan pääsyllä lähdekoodiisi ja salaisuuksiisi.
  • Asennusskriptit ja lataukset. Paketin asennusskripti voi hakea lisää koodia, ja build-vaihe voi ladata binäärin suoraan. Kumpikaan ei jätä merkintää lukitustiedostoon.

Ainoa kattava tallenne siitä, mitkä transitiiviset riippuvuudet päätyivät julkaisuun, on se, joka otetaan julkaisun buildin aikana. Buildin aikana tallennetut SBOM:t selittää eron buildin tallentamisen ja sen tiedostojen jälkikäteisen skannaamisen välillä.

Transitiiviset riippuvuudet ja CRA

EU:n kyberkestävyyssäädös (Cyber Resilience Act, CRA) edellyttää valmistajilta SBOM:ia, joka on "vähintään tuotteiden ylimmän tason riippuvuudet kattava" (liite I, II osa, 1 kohta). Transitiivisia riippuvuuksia ei mainita, joten lain asettama vähimmäistaso on matalampi kuin monet oppaat antavat ymmärtää. CRA edellyttää kuitenkin myös, että tunnistat ja käsittelet tuotteesi sisältämien komponenttien haavoittuvuudet, ja haavoittuva transitiivinen paketti on yksi niistä. Ensimmäiseen tasoon pysähtyvä SBOM jättää suurimman osan riippuvuuspuustasi tuon prosessin ulkopuolelle. Yksityiskohdat löytyvät sivulta CRA:n SBOM-vaatimukset.

Miten CRACI seuraa transitiivisia riippuvuuksia

CRACI on GitHub Actions -runneri, joka tallentaa buildin sen sijaan, että skannaisi sen. Kunkin jobin ajon aikana paketit tunnistava välityspalvelin (proxy) tallentaa jokaisen paketin, jonka jobi hakee, puun jokaisella tasolla, mukaan lukien CI-välimuisteista palautetut paketit. Näin saat kattavamman kuvan käytössä olevista riippuvuuksista kuin skannereihin perustuvilla työkaluilla.

  • Jokainen taso, rehellisesti ilmoitettuna. Jokaisen jobin SBOM:ssa on kattavuustila, joten tiedät, milloin tallennus ei nähnyt kaikkea.
  • Puu näkyvissä. Riippuvuusgraafi näyttää SBOM:n riippuvuuskerrokset useana näkymänä.
  • Viennit, joissa ne ovat mukana. CycloneDX- ja SPDX-viennit sisältävät transitiiviset riippuvuudet, kukin ilmoitetun lisenssinsä kanssa.
  • Mihin buildeihin se vaikutti. Kun uusi haavoittuvuus ilmaantuu, buildihistoria näyttää, mitkä aiemmat buildit sisälsivät haavoittuvan paketin, suorana tai transitiivisena, joten tiedät jakson, jolloin toimitit sitä (katso koskeeko CVE meitä?). Historia noudattaa säilytysaikaasi, oletuksena 180 päivää.
  • Käytäntöportit. Buildi, joka sisältää tietyn CVE:n, voidaan estää ennen kuin se toimitetaan.

CRACI ei tee reachability-analyysiä. Jos sinun on tiedettävä, kutsuuko koodisi haavoittuvaa funktiota, yhdistä se SCA-työkaluun, joka tekee sitä. Katso SBOM-generointi CRACI:ssa tai varaa demo ja tallenna yksi omista buildeistasi.

Transitiiviset riippuvuudet: usein kysytyt kysymykset

Mikä on transitiivinen riippuvuus?

Transitiivinen riippuvuus on paketti, jota ohjelmistosi käyttää, koska jokin toinen paketti tarvitsee sitä. Jos sovelluksesi riippuu kirjastosta A ja A riippuu kirjastosta B, B on sovelluksesi transitiivinen eli epäsuora riippuvuus. Et koskaan ilmoittanut sitä, mutta se toimitetaan ohjelmistosi mukana.

Mitä eroa on suoralla ja transitiivisella riippuvuudella?

Suora riippuvuus on riippuvuus, jonka ilmoitat manifestissasi, kuten package.json-, pyproject.toml- tai go.mod-tiedostossa. Transitiivinen riippuvuus on riippuvuus, jonka suorat riippuvuutesi ilmoittavat, millä tahansa tasolla. Sinä valitset suorat riippuvuudet; paketinhallinta valitsee transitiiviset ratkaistessaan puun.

Onko transient dependency sama kuin transitiivinen riippuvuus?

Käytännössä kyllä. "Transient dependency" on yleinen lipsahdus termin "transitive dependency" sijaan. Oikea termi on transitiivinen, transitiivisesta relaatiosta: jos A riippuu B:stä ja B riippuu C:stä, A riippuu C:stä.

Miten korjaan transitiivisen riippuvuuden haavoittuvuuden?

Päivitä ensin suora riippuvuus, joka tuo sen mukaan, jos siitä on julkaisu korjatulla versiolla. Jos ei ole, pakota korjattu versio paketinhallintasi ohitusmekanismilla, kuten npm:n overrides-asetuksella, Yarnin resolutions-asetuksella tai pipin constraints-tiedostolla, ja testaa, että yläpaketti toimii edelleen sen kanssa.

Miten listaan kaikki transitiiviset riippuvuudet?

Jokainen paketinhallinta osaa tulostaa ratkaistun puun: npm ls --all, pnpm list --depth Infinity, uv tree tai pipdeptree, go mod graph, cargo tree, mvn dependency:tree tai gradle dependencies. Jos haluat tietää, mitä tuotantobuildi todella asensi, tallenna itse buildi.

Edellyttääkö EU:n kyberkestävyyssäädös transitiivisia riippuvuuksia SBOM:ssa?

Asetus asettaa vähimmäistasoksi luettelon, joka on "vähintään tuotteiden ylimmän tason riippuvuudet kattava" (liite I, II osa, 1 kohta). Transitiivisia riippuvuuksia ei mainita, mutta haavoittuva transitiivinen paketti on silti tuotteessasi, ja CRA edellyttää, että käsittelet toimittamiesi komponenttien haavoittuvuudet.

Näe jokainen riippuvuus, jonka buildisi haki

Aja yksi GitHub Actions -työnkulku CRACI:lla ja saat tallennetun SBOM:n jokaisesta sen hakemasta paketista riippuvuuspuun jokaisella tasolla.

Varaa demo