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
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 |
|---|---|
| npm | npm ls --all |
| pnpm | pnpm list --depth Infinity |
| Python (uv) | uv tree |
| Python (pip) | pipdeptree |
| Go | go mod graph |
| Rust | cargo tree |
| Maven | mvn dependency:tree |
| Gradle | gradle 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
- 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.
- 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 uudellanpm update-ajolla. - Ohita versio. Jos yläpaketti ei ole julkaissut korjausta, pakota versio itse:
overridesnpm:ssä ja pnpm:ssä,resolutionsYarnissa, constraints-tiedosto pipillä tai korkeampi vaatimus tiedostossago.mod. Testaa se, koska yläpakettia ei ole koskaan julkaistu tätä versiota vasten. - 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.txttai 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