Confuzie-Dependență-Versiune-Pinning

Lipsa fixării versiunilor și confuzie privind dependențele

În dezvoltarea de software depindem atât de componente sau artefacte proprii, cât și de componente sau artefacte ale unor terțe părți. Un management flexibil al dependențelor este esențial pentru software-ul modern. Manageri de pachete precum NPM, Maven, țâfnă or NuGet sunt adesea folosite pentru a specifica dependențele software. Aceste instrumente au fost proiectate având în vedere confortul și ușurința în utilizare, nu securitatea.

 

Problema

Problema este că flexibilitatea și ușurința în utilizare pentru dezvoltatori îi atrag pe răufăcători, care văd dependențele de software ca fiind irezistibil de fermecătoare pentru afacerea lor. Rezultatul: răufăcătorii au urmat toate căile de atac posibile prezentate aici. Sursa: „Colecția Backstabber's Knife: O recenzie a atacurilor asupra lanțului de aprovizionare cu software open source”

În această postare ne vom concentra pe utilizarea declarațiilor de versiune deschise, în sensul că versiunea descărcată nu este fixă, ci trebuie să aparțină unui anumit interval. La momentul construirii, cea mai înaltă versiune existentă, compatibilă cu intervalul de versiuni specificat, este aleasă și descărcată/instalată de managerul de pachete.

Să ilustrăm declarațiile deschise în declarațiile de dependențe pentru diferiți manageri de pachete:

      • NPM: pachet.json

    {

     

       ...

       „dependențe”: {
          ...
          „acceptă”: „>=1.3.8”,
          „lodash”: „~4.16.0”,
          ...
       },
       ...
    }

    Va fi instalată cea mai mare versiune existentă, nu mai mică decât 1.3.8, pentru pachetul accepts, precum și cea mai mare actualizare „patch” pentru lodash din gama 4.16.x.

        • Maven: pom.xml

      ...

      ...

           commons-io
           commons-io
           ELIBERARE

      ...

      ...

      Ultima versiune disponibilă pentru commons-io (fișierul jar) va fi adăugată ca dependență.

          • pip: setup.py

        ...
        înființat(
            ...
            install_requires=['peppercorn', 'launchpadlib'],
            ...
        )
        ...

        Astfel de scheme de versiuni deschise au o parte bună și una proastă. Partea bună este că versiunile mai noi obișnuit conțin îmbunătățiri funcționale și de calitate, corecții de erori și patch-uri de securitate, care sunt actualizate automat. Rețineți că, pentru majoritatea proiectelor din lumea reală, remedierile nu sunt adaptate la versiunile minore anterioare, cu excepția, poate, a vulnerabilităților de securitate catastrofale. Versiunile deschise sunt, de asemenea, potrivite pentru utilizarea în biblioteci, pentru a reduce numărul de versiuni care trebuie instalate atunci când toate dependențele sunt rezolvate.

        Însă intervalele de versiuni deschise au și o parte negativă. Nu știi exact ce versiuni vor fi instalate în momentul construirii, iar construcțiile nu sunt repetabile. Și există, de asemenea, o întuneric de partea versiunilor deschise. Dacă un atacator reușește să publice o componentă rău intenționată în depozitul public cu o versiune superioară compatibilă cu intervalul deschis, următoarea versiune va include componenta rău intenționată, eventual chiar executând programe malware în scripturi de instalare care ar putea fi executate automat. Obfuscarea sarcinii utile a atacului este o adevărată artă.

        Aceasta este cunoscută sub numele de Lipsa fixării versiunii problema.

        Actorii rău intenționați încearcă mereu să introducă versiuni rău intenționate ale unor pachete open-source populare. Aceștia pot obține acces la cheile depozitelor de pachete într-o scurgere secretă; adesea folosesc ingineria socială sau ascund o dependență rău intenționată imbricată într-un dispozitiv aparent util. pull requestChiar și câțiva autori decid într-o zi că lumea nu este dreaptă și își mușcă clienții cu protestware în propriile lor pachete!

        Acum imaginează-ți că lucrezi pentru o organizație care folosește componente interne plus componente open-source.
        Dacă un rău intenționat cunoaște numele unor astfel de componente interne, acesta poate reuși să publice o componentă cu același nume în depozitul public. Mulți manageri de pachete preiau mai întâi componentele publice, iar dacă versiunea este aleasă corect și versiunea din dependența declarată este deschisă, bum! Această problemă se numește Confuzie privind dependența.

        Să arătăm un exemplu. Să presupunem că în proiectul nostru NPM avem o dependență de o componentă privată:

            • NPM: pachet.json

          {
            "nume": "proiectul-meu",

           

            ...
            „dependențe”: {

              ...
              „departamentul-meu-privat”: „>=1.0.0”,

              ...

             }

             ...

          }

           

          Atacatorul poate crea o versiune majoră a depozitului my-private-dep (cum ar fi 99.0.0) și o poate publica în depozitul public npm, cu propriul cont fals (atacatorul nu trebuie să facă nimic cu organizația mea). Managerul de pachete NPM va instala dependența rău intenționată, adesea cu rezultate devastatoare.

          Soluția

          Pentru a evita aceste probleme în procesul de construire a software-ului nostru, ar trebui să urmăm norme stricte privind modul de declarare a versiunilor componentelor, care depind de tehnologia utilizată. Important este ca o anumită versiune a unui pachet, odată publicată într-un repozitoriu, să fie imuabilă (pentru a evita încălcarea dependențelor, nu doar din motive de securitate).

          Ideea generală este de a fixa (pinul), verificând întotdeauna dacă versiunile fixe ale componentelor (inclusiv TOATE dependențele tranzitive) nu conțin programe malware, iar acest lucru este posibil datorită fișiere de blocare pe care le oferă mulți manageri de pachete. Să vedem cum funcționează fixarea versiunilor pentru diferiți manageri de pachete. Există un compromis delicat între actualizări frecvente ale versiunilor pentru remedierea vulnerabilităților cunoscute și fixarea versiunii pentru a evita construcțiile nedeterministe și potențialele atacuri asupra lanțului de aprovizionare.

              • NPM:
                Managerii de pachete npm sau yarn utilizează fișiere de blocare diferite (npm-shrinkwrap.json / package-lock.json sau yarn.lock, respectiv) care listează versiunile fixe pentru toate dependențele, directe și indirecte. Fișierele de blocare ar trebui să fie sub controlul versiunilor, altfel alți dezvoltatori / noduri de compilare pot termina cu versiuni diferite. Evitați instalarea npm, cu excepția cazului în care, în timpul dezvoltării, trebuie să actualizați dependențele (de exemplu, pentru a instala corecții de securitate). Folosiți în general versiunea de sincronizare npm (Clean Install), mai deterministă, astfel încât managerul de pachete să utilizeze fișierul de blocare sau să se termine cu eroare dacă nu există niciun fișier de blocare sau dacă acesta nu se potrivește cu package.json. Dacă versiunile listate au fost verificate pentru malware, fișierul de blocare asigură că nu se va întâmpla nimic rău în momentul compilării.

                Pentru componentele interne, se recomandă crearea unui Domeniul de aplicare al NPM gestionat de organizație (cum ar fi @myorg) și să utilizeze acel domeniu de aplicare în dependență (cum ar fi @myorg/my-private-dep), care ar putea avea doar vizibilitate privată. Aceasta blochează confuzie de dependență atacuri, deoarece doar membrii organizației cu acces de scriere pot publica pachete în acest domeniu.

              • Maven:
                Maven / Gradle nu au fișiere de blocare (dar vezi acest articol StackOverflow).

                Intervalele de versiuni nu sunt utilizate cu Maven/Gradle la fel de mult ca în alte ecosisteme. Evitați doar intervale de versiuni și meta-versiunile ULTIME sau VERIFICARE. Versiunile indirecte ar trebui, de asemenea, verificate. Versiuni Maven Plugin este un instrument bun pentru controlul versiunilor.

                Rețineți că Maven a avut întotdeauna conceptul de domeniu de aplicare al organizației (partea groupId a dependenței), iar confuzia dintre dependențe nu pare a fi deloc o problemă pentru acel ecosistem.

              • Țâfnă:
                În Python există diferite instrumente pentru gestionarea fișierelor de blocare:

                - pipenv, care generează un fișier de blocare Pipfile.lock.
                - poezie, care generează poetry.lock.
                - înghețarea pip-urilor, comandă care generează un fișier requirements.txt ce acționează ca un fișier de blocare. Verifică dacă toate dependențele utilizează versiuni fixe cu operatorul ==. Apoi, comanda pip install -r requirements.txt utilizează dependențele fixe.

            Rețineți că fișierele de blocare de mai sus ar trebui să fie sub controlul versiunilor și că comanda de compilare aleasă ar trebui să utilizeze fișierul de blocare.

            Depozitul de pachete obișnuit folosit cu pip (PyPI) nu are domenii de aplicare a denumirii și este vulnerabil la atacuri de confuzie a dependenței. Evitarea confuziei legate de dependențe în ecosistemul Python nu este ușor, iar unii autori recomandă utilizarea unui repozitoriu intern care să acționeze ca proxy pentru dependențele publice preluate din PyPI, dar preluarea mai întâi a dependențelor private din repozitoriul intern (-index-url ar trebui să indice către repozitoriul intern, nu către PyPI, iar –extra-index-url ar trebui eliminat).

            Câteva atacuri reale

            Atacul GetcookiesActorul dustin87 a adăugat o dependență indirectă în popularul pachet npm mailparser la un pachet malițios cu un backdoor RCE (gCOMMANDhDATAi):

            JSON.stringify(req.headers).replace(/g([a-f0-9]{4})h((?:[a-f0-9]{2})+)i/gi, (o, p, v) => {})

            Deși era depreciat (fără recenzori!), mailparser primea totuși aproximativ 64,000 de descărcări săptămânale. Acesta a fost un caz de atac ratat la limită, deoarece RCE nu era de fapt exercitat.cised.

            NPM a publicat acest post cu detalii despre atacul getcookies.

            Confuzie privind dependența:

            Alex Birsan a descoperit în 2021 problema confuziei legate de dependențe și a publicat o postare intitulată „Cum am spart Apple, Microsoft și zeci de alte companii".

            Rețineți că pentru npm, domeniul de aplicare al organizației, cum ar fi @myorg, ar trebui rezervat, iar pachetele interne ar trebui modificate pentru a utiliza acest domeniu.

            Cu pip, registrul public comun PyPI nu are domenii de aplicare/spații de nume. Fiecare pachet privat ar putea avea un squat de pachete public cu același nume ca și pachetul intern, dar gol și care poate genera o eroare atunci când este utilizat, astfel încât să poată fi identificat dacă este preluat accidental.

            Nod-ipc:

            Proprietarul pachetului, când a început războiul dintre Rusia și Ucraina, a injectat cod malițios pentru eliminarea fișierelor aleatorii, atunci când acestea erau instalate pe gazdele rusești și belaruse. Fișierul ssl-geospec.js făcea următoarea distincție geografică:

            Interesant este că alte pachete au folosit versiuni deschise pentru dependența node-ipc, cum ar fi popularul framework Vue.js, iar administratorii acestuia au primit o... apel urgent pentru a fixa dependența node-ipc pe o versiune sigură.

            Aceasta postarea conține mai multe detalii despre acest sabotaj, care merge cu un pas mai departe decât altele Protestware probleme.

             

            Concluzii finale

            Versiunile deschise ar trebui nu pot fi utilizate în proiecte software consolidate. Acestea fac ca versiunile să nu fie reproductibile, iar atacatorii le pot exploata și pot reuși să injecteze programe malware prin atacuri asupra arborilor de dependențe, cum ar fi confuzia de dependențe menționată anterior.

            Configurații greșite precum versiuni deschise, lipsa fixării versiunilor sau componente interne nedelimitate ar trebui evitate. Primul lucru este să se detecteze astfel de probleme, poate chiar să se blocheze construcția atunci când sunt descoperite, și să se standardizeze un protocol de acțiune.

            Detectarea automată a defectelor și configurațiilor greșite în dependențe, raportând dependențele suspecte care ar putea fi vulnerabile la atacuri specifice ale lanțului de aprovizionare, cum ar fi confuzie de dependență, toate cu instrumente de remediere acționabile, este unul dintre principalele obiective ale Platforma Xygeni.

            Pentru a citi mai mult
            Ohm M., Plate H., Sykosch A., Meier M.: „Colecția Backstabber's Knife: O recenzie a atacurilor din lanțul de aprovizionare cu software open source”. DIMVA 2020. Lecture Notes in Computer Science, vol. 12223. Springer – 2020 (sursa figurii arborelui de atac al dependențelor.)
            @adam-npm: „Modul rău intenționat raportat: getcookies„. Blogul npm (arhivat) – 2 mai 2018.”
            Alex Bîrsan: „Cum am spart Apple, Microsoft și zeci de alte companii„”. Medium – 9 februarie 2021.
            Ax Sharma: „MARE sabotaj: Celebrul pachet npm șterge fișiere în semn de protest împotriva războiului din Ucraina„BleepingComputer – 17 martie 2022”

            sca-tools-software-instrumente-de-analiză-a-compoziției
            Prioritizați, remediați și securizați riscurile software
            Obține-ți contul gratuit.
            Nu este necesar un card de credit.

            Securizează-ți dezvoltarea și livrarea de software

            cu suita de produse Xygeni