A szoftverellátási lánc biztonsága úgy hangzik, mint azoknak a szervezeteknek a gondja, amelyeknek van saját biztonsági csapatuk, és éppen ez a keretezés vezet félre. Egy kis csapat, amely néhány szolgáltatást üzemeltet, jellemzően több száz olyan csomagtól függ, amelyet közülük soha senki nem olvasott végig. Ezek a csomagok build közben érkeznek olyan registryből, amely nem a csapat kezében van, és telepítési szkripteket futtatnak azokon a gépeken, ahol a telepítési kulcsok és hozzáférések állnak.

A kitettség nem a cégmérettel arányos. A függőségek számával és a build automatizáltságával arányos, a kis csapatoknál pedig az elsőből gyakran több van, a másodikra viszont kevesebben néznek rá, mint azoknál a szervezeteknél, amelyek nyilvánosan aggódnak emiatt a téma miatt.

A kényelmetlen számtan: az alkalmazásodnak talán egy tucat közvetlen függősége van, és több száz áttételes függősége. A tucatot te választottad ki. A többit nem, egyet sem olvastál el közülük, és bármelyikük, amint egy telepítési szkriptet futtat, ugyanazt a hozzáférést kapja, mint a build folyamatod. Ez a tényleges támadási felület, és abból a függőségi listából, amelyet te írtál, egyáltalán nem látszik.


A szoftverellátási lánc biztonsága a telepítésnél kezdődik

A veszélyes pillanat általában nem a kód futtatása. Hanem a telepítése.

A csomagkezelők megengedik, hogy a telepítés közben szkriptek fussanak le. Ez azt jelenti, hogy egy feltört vagy szándékosan rosszindulatú csomag annak a jogosultságaival fut, aki a telepítést elindította. Egy fejlesztői gépen ez az illető saját hozzáféréseit jelenti. Egy build pipeline-ban viszont a telepítési kulcsokat, és ez lényegesen rosszabb kimenetel.

Három támadási forma adja a valós incidensek túlnyomó részét.

Typosquatting. Olyan csomag, amelynek a neve egyetlen karakterben tér el egy népszerű csomagétól, közzétéve és arra várva, hogy valaki elgépelje a telepítési parancsot. Olcsó kivitelezni, és nagy léptékben eredményes.

Egy legitim csomag fiókjának feltörése. Egy széles körben használt csomag, amelynek a karbantartójától ellopták a belépési adatait, majd valami ártalmassal egészítették ki. Ez ellen a legnehezebb védekezni, mert sem a név, sem a letöltésszám nem mutat semmi gyanúsat.

Dependency confusion. Nyilvános csomag, amelyet valamelyik belső csomagod nevén tesznek közzé, miközben egy rosszul konfigurált resolver a nyilvános registryt részesíti előnyben a sajátoddal szemben. Teljes egészében konfigurációs probléma, és teljes egészében megelőzhető.

Egyik támadáshoz sem kell, hogy bárki kifejezetten téged vegyen célba, és éppen ez a lényeg. Alkalmi jellegűek, és jól skálázódnak.

Kontrollok, amelyek kis léptékben is megérik

Tedd be a lockfile-t a repóba, és abból telepíts. A lockfile pontos verziókat és a hozzájuk tartozó hasheket rögzíti. Ha ehelyett a manifestből telepítesz, a build ideje alatt friss verziók oldódnak fel, vagyis a build nem reprodukálható, és egy fentről érkező változás átvizsgálás nélkül jut ki éles környezetbe. Azt a telepítési parancsot használd, amelyik hibával leáll, ha a lockfile nem egyezik, ne azt, amelyik csendben frissíti.

Kapcsold ki a telepítési szkripteket, ahol csak lehet. Sok ökoszisztéma támogatja ezt, és a csomagok többségének nincs is szüksége rájuk. Ez a legnagyobb egyetlen kitettségcsökkentés, amelyhez külön eszköz nélkül hozzájutsz, az a néhány csomag pedig, amelyik emiatt elromlik, pontosan az, amelyikről érdemes tudnod.

Automatizáld a sérülékenységi riasztásokat, aztán rangsorold őket. A szkennerek több találatot állítanak elő, mint amennyit egy kis csapat feldolgozni képes, és a hibamód nem az elszalasztott riasztás, hanem az összes riasztás figyelmen kívül hagyása, mert a többségük nem érint téged. Szűrj arra, ami a saját kódodból ténylegesen elérhető, és azzal foglalkozz. Egy sor, amelyet senki nem olvas el, rosszabb, mintha egyáltalán nem lenne sor.

Rögzítsd a build eszközeit is. A konténerkép, a futtatókörnyezet verziója, valamint az action vagy a plugin, amelyet a pipeline hív, szintén függőségek, és ha változtatható címkére hivatkozol egy változtathatatlan lenyomat helyett, akkor a buildod nélküled változik meg.

Válaszd külön a build hozzáféréseit mindentől. Egy pipeline, amely telepíthet éles környezetbe, ne tartson olyan hozzáféréseket, amelyekkel ennél többet is lehet kezdeni, egy feltört build pedig ne érhesse el az éles adatokat.

Mit mond el egy SBOM, és mit nem

A szoftverösszetevő-jegyzék, röviden SBOM, felsorolja, mi van az alkalmazásodban, és az értéke abban áll, hogy egyetlen kérdésre gyorsan válaszol: érint minket ez?

Ez a kérdés korábban napokat vett el. Amikor kiderül egy széles körben használt komponensről, hogy sérülékeny, egy naprakész leltárral rendelkező szervezet percek alatt válaszol, egy leltár nélküli pedig egy hetet tölt kereséssel. Ez a különbség maga a teljes érvelés, és emiatt ösztönzik az SBOM bevezetését alapgyakorlatként, nem pedig haladó kontrollként.

Amit viszont nem tesz meg: nem tesz biztonságossá. A leltár egy lista, nem védelem. Nem mondja meg, hogy egy felsorolt sérülékenység elérhető-e a saját kódodból, hogy számít-e a te konfigurációdban, és azt sem, hogy történt-e már valahol behatolás. Az a csapat, amely legyárt egyet és elteszi, egy dokumentummal lett gazdagabb, nem egy kontrollal.

A buildből állítsd elő, hogy azt írja le, ami ténylegesen kikerült, ne azt, amit a manifest állított. Őrizd meg azt a példányt, amelyik az adott kiadáshoz tartozik. És fogadd el, hogy az értéke teljes egészében abban a sebességben van, amellyel egy nyomás alatt feltett kérdésre válaszolni tudsz.

Hol sérülnek meg valójában a kis csapatok

Ritkán egy egzotikus csomagfeltörés miatt. Hétköznapi dolgok miatt.

Titkok a repóban, amelyek törlés után is bent maradnak az előzményekben, és amelyeket automatizált szkennerek a push után percekkel megtalálnak. Egy három éve nem frissített függőség közzétett exploittal és járható frissítési útvonal nélkül, mert a verzióemelést addig halasztották, amíg önálló projektté nem nőtte ki magát. Túl tág jogosultságú build pipeline-ok, ahol egy forkból érkező pull request olyan hozzáférésekkel fut, amelyekkel nem szabadna. Senki nem figyeli, így egy behatolás hosszan fennmarad, mert egyetlen riasztás sem jut el emberhez.

A csöppet sem látványos következtetés az, hogy a függőségek naprakészen tartása a gyakorlatban kiadja a szoftverellátási lánc biztonságának javát. A szoftverkarbantartás költsége, amelyet a csapatok opcionálisnak tekintenek, pontosan ugyanez a munka, és a halogatása egy rutinfrissítést változtat vészhelyzetté, mellékelt exploittal együtt.

Arányos kiindulópont

Egy kis csapatnak ebben a sorrendben: szedd ki a titkokat a repóból, és cseréld le mindazt, ami kikerült. Tedd be a lockfile-okat, és szigorúan azokból telepíts. Kapcsold be a függőségi riasztásokat, és hetente rangsorold őket, ne folyamatosan. Rögzítsd a build eszközeit változtathatatlan hivatkozásokra. Csökkentsd a pipeline jogosultságait a szükséges minimumra. Készíts SBOM-ot kiadásonként, amint a többi már a helyén van.

Ez a sorrend lefedi a valós fenyegetéseket saját biztonsági csapat nélkül is, és minden lépés órákban mérhető, nem hetekben. Az ezen túli kontrollok, vagyis az eredetigazolás, a reprodukálható buildek és az aláírt artefaktumok, valóban értékesek, de abba a szakaszba tartoznak, ahol az alapok már stabilan működnek.

A Mecanik a build pipeline-okat átvizsgálja és megerősíti az alkalmazás biztonsági elemzés keretében. A lelet szinte soha nem egy kifinomult támadás. Egy token a repóban és egy függőség, amelyet a kiválasztása óta senki nem frissített.



Gyakran ismételt kérdések

Miért a csomagok telepítése a kockázatos pillanat? Mert a csomagkezelők megengedik, hogy a telepítés közben szkriptek fussanak le, annak a jogosultságaival, aki a telepítést elindította. Fejlesztői gépen ez az illető hozzáféréseit jelenti, egy build pipeline-ban pedig a telepítési kulcsokat. A kódot nem is kell futtatnia az alkalmazásodnak ahhoz, hogy kárt okozzon.

Mi az a dependency confusion? Olyan támadás, amelyben egy nyilvános csomagot valamelyik belső csomagod nevén tesznek közzé, egy rosszul konfigurált resolver pedig a nyilvános registryt részesíti előnyben a sajátoddal szemben. Nem kell hozzá, hogy bárki kifejezetten téged célozzon meg, és a resolver helyes beállításával teljes egészében megelőzhető.

Mit ad valójában egy SBOM? Gyors választ egyetlen kérdésre: érint minket ez? Naprakész leltárral ez percek kérdése, leltár nélkül egy hét keresés. Nem mondja meg, hogy egy felsorolt sérülékenység elérhető-e a kódodból, és azt sem, hogy történt-e már behatolás, így az az SBOM, amelyet legyártanak és eltesznek, dokumentum marad, nem kontroll.

Be kell tennem a lockfile-t a repóba? Igen, és szigorúan abból telepíts, azzal a paranccsal, amelyik hibával leáll, ha a lockfile nem egyezik, nem azzal, amelyik frissíti. Ha a manifestből telepítesz, a build ideje alatt friss verziók oldódnak fel, a buildek nem lesznek reprodukálhatók, és egy fentről érkező változás mindenféle átvizsgálás nélkül jut ki éles környezetbe.

Hol kezdje egy kis csapat? Vedd ki a titkokat a repóból és cseréld le mindazt, ami kikerült, tedd be a lockfile-okat és szigorúan azokból telepíts, kapcsold be a függőségi riasztásokat és hetente rangsorold őket, rögzítsd a build eszközeit változtathatatlan hivatkozásokra, csökkentsd a pipeline jogosultságait, majd készíts SBOM-ot kiadásonként. Minden lépés órákban mérhető, nem hetekben.