En el desenvolupament de programari depenem tant de components o artefactes propis com de tercers. Una gestió de dependències flexible és essencial per al programari modern. Gestors de paquets com NPM, Maven, pip or NuGet sovint s'utilitzen per especificar dependències de programari. Aquestes eines es van dissenyar tenint en compte la comoditat i la facilitat d'ús, no la seguretat.
El problema
El problema és que la flexibilitat i la facilitat d'ús per als desenvolupadors criden l'atenció dels malfactors, que veuen les dependències de programari com un encant irresistible per al seu negoci. El resultat: els malfactors van seguir totes les rutes d'atac possibles que es mostren aquí. Font: "Backstabber's Knife Collection: A Review of Open Source Software Supply Chain Attacks"
En aquesta publicació ens centrarem en l'ús de declaracions de versió oberta, en el sentit que la versió descarregada no és fixa sinó que ha de pertànyer a un rang determinat. En temps de compilació, el gestor de paquets tria i descarrega/instal·la la versió més alta existent compatible amb el rang de versions especificat.
Il·lustrem les declaracions obertes en les declaracions de dependències per a diferents gestors de paquets:
- NPM: paquet.json
{
...
"dependències": {
...
«accepta»: «>=1.3.8»,
«lodash»: «~4.16.0»,
...
},
...
}
S'instal·larà la versió més gran existent no inferior a l'1.3.8 per al paquet accepts, així com l'actualització de "pegat" més gran per a lodash en el rang 4.16.x.
- Maven: pom.xml
...
...
commons-io
commons-io
PUBLICACIÓ
...
...
L'última versió disponible per a commons-io (fitxer jar) s'afegirà com a dependència.
- Pip: setup.py
...
configuració (
...
install_requires=['peppercorn', 'launchpadlib'],
...
)
...
Aquests esquemes de versions obertes tenen un costat bo i un de dolent. El bo és que les versions més noves generalment Conté millores funcionals i de qualitat, correccions d'errors i pegats de seguretat, que s'actualitzen automàticament. Tingueu en compte que per a la majoria de projectes del món real, les correccions no es retroporten a versions menors anteriors, excepte potser per vulnerabilitats de seguretat catastròfiques. Les versions obertes també són bones per al seu ús en biblioteques, per reduir el nombre de versions que cal instal·lar quan es resolen totes les dependències.
Però els rangs de versions obertes tenen un costat negatiu. No se sap exactament quines versions s'instal·laran en el moment de la compilació, i les compilacions no són repetibles. I també hi ha un fosc costat amb versions obertes. Si un actor malintencionat aconsegueix publicar un component maliciós al repositori públic amb una versió alta compatible amb el vostre rang obert, la vostra propera compilació inclourà el component maliciós, potser fins i tot executant programari maliciós en scripts d'instal·lació que es podrien executar automàticament. Ofuscar la càrrega útil de l'atac és tot un art.
Això es coneix com a Manca de fixació de versions assumpte.
Els malfactors sempre intenten posar versions malicioses de paquets populars de codi obert. Poden obtenir accés a les claus dels repositoris de paquets en una filtració secreta; sovint utilitzen enginyeria social o amaguen una dependència maliciosa imbricada en un lloc aparentment útil. pull requestFins i tot alguns autors decideixen un dia que el món no és just i mosseguen els seus clients amb material de protesta en els seus propis paquets!
Ara imagina que treballes per a una organització que utilitza components interns a més de components de codi obert.
Si un mal actor coneix el nom d'aquests components interns, pot aconseguir publicar un component amb el mateix nom al repositori públic. Molts gestors de paquets obtenen primer els components públics, i si la versió s'ha triat correctament i la versió de la dependència declarada està oberta, boom! Aquest problema s'anomena Confusió de dependència.
Mostrem un exemple. Suposem que al nostre projecte NPM tenim una dependència d'un component privat:
- NPM: paquet.json
{
"nom": "el-meu-projecte",
...
"dependències": {...
“la-meva-divisió-privada”: “>=1.0.0”,...
}
...
}
L'atacant pot crear una versió major de my-private-dep (com ara 99.0.0) i publicar-la al repositori públic npm, amb el seu propi compte fals (l'atacant no ha de fer res amb la meva organització). El gestor de paquets NPM instal·larà la dependència maliciosa, sovint amb resultats devastadors.
La solució
Per evitar aquests problemes en el nostre procés de compilació de programari, hauríem de seguir normes estrictes sobre com declarar les versions dels components, que depenen de la tecnologia utilitzada. L'important és que una versió específica d'un paquet, un cop publicada en un repositori, sigui immutable (per evitar trencar dependents, no només per motius de seguretat).
La idea general és fixar (pin), comprovant sempre que les versions fixes dels components (incloses TOTES les dependències transitives) estiguin lliures de programari maliciós, i això és possible gràcies a la fitxers de bloqueig que ofereixen molts gestors de paquets. Vegem com funciona la fixació de versions per a diferents gestors de paquets. Hi ha un delicat compromís entre actualitzacions freqüents de la versió per solucionar vulnerabilitats conegudes i fixació de versions per evitar compilacions no deterministes i possibles atacs a la cadena de subministrament.
- NPM:
Els gestors de paquets npm o yarn utilitzen fitxers de bloqueig diferents (npm-shrinkwrap.json / package-lock.json o yarn.lock, respectivament) que llisten versions fixes per a totes les dependències, directes i indirectes. Els fitxers de bloqueig haurien d'estar sota control de versions; en cas contrari, altres desenvolupadors / nodes de compilació poden acabar amb versions diferents. Eviteu la instal·lació de npm tret que durant el desenvolupament necessiteu actualitzar les dependències (per exemple, per instal·lar correccions de seguretat). En general, utilitzeu la ci npm (instal·lació neta) més determinista, de manera que el gestor de paquets utilitzarà el fitxer de bloqueig o finalitzarà amb error si no hi ha cap fitxer de bloqueig o no coincideix amb el package.json. Si les versions llistades s'han comprovat per detectar programari maliciós, el fitxer de bloqueig garanteix que no passarà res dolent en temps de compilació.Per als components interns, es recomana crear un Àmbit de NPM gestionat per l'organització (com ara @myorg) i utilitzar aquest àmbit a la dependència (com ara @myorg/my-private-dep), que només podria tenir visibilitat privada. Això bloqueja confusió de dependències atacs, ja que només els membres de l'organització amb accés d'escriptura poden publicar paquets sota aquest àmbit.
- NPM:
- Maven:
Maven / Gradle no tenen fitxers de bloqueig (però vegeu aquest article de StackOverflow).Els rangs de versions no s'utilitzen tant amb Maven/Gradle com amb altres ecosistemes. Només cal evitar-ho. intervals de versions i metaversions ÚLTIMES o VERSIONS. També s'han de comprovar les versions indirectes. El/La Versions del complement Maven és una bona eina per al control de versions.
Tingueu en compte que Maven sempre ha tingut el concepte d'abast de l'organització (la part groupId de la dependència) i la confusió de dependències no sembla ser un problema en absolut per a aquest ecosistema.
- Maven:
- Pip:
A Python hi ha diferents eines per gestionar fitxers de bloqueig:- pipenv, que genera un fitxer de bloqueig Pipfile.lock.
- poesia, que genera poetry.lock.
- pip freeze, comanda que genera un fitxer requirements.txt que actua com a fitxer de bloqueig. Comproveu si totes les dependències utilitzen versions fixes amb l'operador ==. Aleshores, pip install -r requirements.txt utilitza les dependències fixes.
- Pip:
Recordeu que els fitxers de bloqueig anteriors haurien d'estar sota control de versions i que l'ordre de compilació escollida hauria d'utilitzar el fitxer de bloqueig.
El repositori de paquets habitual que s'utilitza amb pip (PyPI) no té àmbits de noms i és vulnerable a atacs de confusió de dependències. Evitant la confusió de dependències a l'ecosistema Python no és fàcil, i alguns autors recomanen utilitzar un repositori intern per actuar com a intermediari de les dependències públiques obtingudes de PyPI, però agafant primer les dependències privades del repositori intern (-index-url hauria d'apuntar al repositori intern, no a PyPI, i s'hauria de suprimir –extra-index-url).
Alguns atacs reals
Atac de GetcookiesL'actor dustin87 ha afegit una dependència indirecta al popular paquet npm mailparser a un paquet maliciós amb una porta del darrere RCE (gCOMMANDhDATAi):
JSON.stringify(req.headers).replace(/g([a-f0-9]{4})h((?:[a-f0-9]{2})+)i/gi, (o, p, v) => {})Tot i estar obsolet (sense revisors!), Mailparser encara rebia unes 64,000 descàrregues setmanals. Aquest va ser un cas d'atac quasi accidental, ja que l'RCE no estava realment exercint.cised.
NPM publicat aquest post amb detalls sobre l'atac getcookies.
Confusió de dependència:
Alex Birsan va descobrir el problema de la confusió de les dependències el 2021 i va publicar una entrada titulada "Com vaig piratejar Apple, Microsoft i desenes d'altres empreses".
Recordeu que per a npm l'àmbit de l'organització com ara @myorg s'ha de reservar i els paquets interns s'han de modificar per utilitzar l'àmbit.
Amb pip, el registre públic comú PyPI no té àmbits/espais de noms. Cada paquet privat podria tenir un squat de paquets públic amb el mateix nom que el paquet intern, però buit, i potser generant un error quan s'utilitza, de manera que es podria identificar si s'obté accidentalment.
Node-ipc:
El propietari del paquet, quan va començar la guerra entre Rússia i Ucraïna, va injectar codi maliciós per eliminar fitxers aleatoris, quan s'instal·laven en hosts russos i bielorussos. El fitxer ssl-geospec.js feia aquesta distinció geogràfica:
Curiosament, altres paquets utilitzaven versions obertes per a la dependència node-ipc, com el popular framework Vue.js, i els seus mantenidors van rebre una crida urgent per fixar la dependència node-ipc a una versió segura.
aquesta la publicació conté més detalls sobre aquest sabotatge, que va un pas més enllà d'altres Protesta problemes.
Observacions finals
Les versions obertes haurien de mai es poden utilitzar en projectes de programari consolidats. Fan que les compilacions no siguin reproduïbles i els atacants poden explotar-les i aconseguir injectar programari maliciós mitjançant atacs als arbres de dependències com la confusió de dependències esmentada anteriorment.
Configuracions incorrectes com ara versions obertes, manca de fixació de versions o components interns sense àmbit s'hauria d'evitar. El primer és detectar aquests problemes, potser fins i tot bloquejar la compilació quan es trobin, i haver estandarditzat un protocol d'acció.
Detecció automàtica de defectes i configuracions incorrectes en dependències, informant de dependències sospitoses que podrien ser vulnerables a atacs específics de la cadena de subministrament com ara confusió de dependències, tot amb eines de correcció accionables, és un dels principals objectius de la Plataforma Xygeni.
| Per llegir més |
| Ohm M., Plate H., Sykosch A., Meier M.: “Backstabber's Knife Collection: A Review of Open Source Software Supply Chain Attacks”. DIMVA 2020. Lecture Notes in Computer Science, vol. 12223. Springer – 2020 (font de la figura de l'arbre d'atacs de dependències). |
| @adam-npm: “Mòdul maliciós reportat: getcookies«. Blog de npm (arxivat) – 2 de maig de 2018.» |
| Àlex Birsan:Com vaig piratejar Apple, Microsoft i desenes d'altres empreses". Medium – 9 de febrer de 2021. |
| Ax Sharma: “GRAN sabotatge: el famós paquet npm elimina fitxers per protestar contra la guerra d'Ucraïna” BleepingComputer – 17 de març de 2022 |







