Безпека ланцюга постачання
Щодо самих заходів контролю та щоденних процедур див. Керування залежностями. Суміжні теми безпеки мають власні розділи: привілеї тригерів робочих процесів і токенів — у CI-робочих процесах, а повідомлення про вразливості — у політиці безпеки.
Модель загроз
Серпневий хробак npm 2026 року (повідомлення про безпеку) визначив поточну позицію: зламані облікові записи підтримувачів публікували шкідливі версії популярних npm-пакунків. Скрипти життєвого циклу пакунків, які виконуються під час встановлення, запускали корисне навантаження та поширювали його за допомогою викрадених облікових даних. До стримування було уражено кілька PR-гілок цього репозиторію; жодна не досягла main або виробничого середовища.
Шляхи атак, важливі для цього репозиторію:
- Визначення версій: будь-яке встановлення, яке визначає діапазони версій, може завантажити щойно опублікований шкідливий випуск.
- Скрипти життєвого циклу: виконання скриптів під час встановлення дозволяє шкідливому пакунку скомпрометувати хости учасників, виконавців CI та образи збірки.
- Встановлення без нагляду: завдання CI та образ збірки Netlify встановлюються без нагляду людини, як і сеанси агентів.
- Визначення назв: виклик інструмента, який може звернутися до реєстру за назвою (
npx), виконує той пакунок, якому належить ця назва, коли локальне встановлення застаріле або відсутнє.
Рішення щодо дизайну
Наскрізна тема — закриватися при збої (fail closed): коли захід контролю неможливо забезпечити, встановлення завершується збоєм, а не продовжується без нього.
Кожне рішення відповідає шляху атаки, упорядковані приблизно за моментом дії. Підсумкова таблиця зіставляє рішення з їхнім забезпеченням.
- Кожна залежність, пряма чи транзитивна, — це поверхня, якої може досягти нападник.
- Встановлення, яке визначає діапазони версій, може завантажити щойно опублікований шкідливий випуск.
- Встановлення з блокування: встановлення є точними щодо блокування, відтворюючи зафіксований і перевірений
package-lock.json. Єдиний виняток: локальнийnpm installможе перезаписати незгодне блокування; такі перезаписи виявляє перевірка. - Явне визначення версій: визначення версій відбувається лише під час навмисних оновлень залежностей, ніколи як побічний ефект встановлення.
- Визначення версій лише для випусків, що відстоялися: навіть явне визначення версій ігнорує випуски, молодші за період охолодження; відкликання шкідливих випусків на стороні реєстру потребує кількох днів.
- Встановлення з блокування: встановлення є точними щодо блокування, відтворюючи зафіксований і перевірений
- Скрипти пакунка, що виконуються під час встановлення, запускають код нападника на хостах учасників та машинах збірки: шлях корисного навантаження хробака.
- Виконуються лише перевірені скрипти життєвого циклу: скрипти життєвого циклу є стандартно забороненими.
- Схвалення є точними щодо версії, тому скомпрометований патч-випуск не може успадкувати схвалення свого попередника.
- Перевірки фіксують і заборони, тож відсутність відповіді завжди означає «не перевірено».
- Винятки називаються та повторно вмикаються безпосередньо в місці використання, ніколи не послаблюючи стандартну позицію.
- Виконуються лише перевірені скрипти життєвого циклу: скрипти життєвого циклу є стандартно забороненими.
- Власне встановлення npm Netlify виконується без нагляду, поза скриптами, які контролює цей репозиторій, і його неможливо вимкнути.
- Нейтралізація автоматичного встановлення: конфігурація нейтралізує його; команда збірки виконує справжнє встановлення.
- Бінарний файл, викликаний за назвою, яку можна визначити через реєстр, виконує те, що претендує на цю назву, коли локальне встановлення застаріле; сквотінг незареєстрованої назви бінарного файлу довів це у червні.
- Викликайте бінарні файли, а не назви: обвʼязка репозиторію ніколи не використовує голий
npx; бінарні файли беруться зі встановленого дерева залежностей або завершуються гучним збоєм.
- Викликайте бінарні файли, а не назви: обвʼязка репозиторію ніколи не використовує голий
- Захід контролю, який мовчки перестає застосовуватися, гірший за його відсутність.
Забезпечення з першого погляду:
| Рішення | Забезпечується |
|---|---|
| Мінімізація залежностей | Рішення підтримувача під час перегляду залежностей; механічного контролю немає |
| Встановлення з блокування | npm ci у кожному контракті встановлення |
| Явне визначення версій | Конвенція, підкріплена блокуванням: неочікуване визначення перезаписує його, що позначає перевірка |
| Визначення версій лише для випусків, що відстоялися | Захід охолодження, однаково для npm та Renovate |
| Виконання лише перевірених скриптів життєвого циклу | Дозволений список у строгому режимі; неперевірене завершує встановлення збоєм |
| Нейтралізація автоматичного встановлення | Захід інертного автоматичного встановлення |
| Викликайте бінарні файли, а не назви | Правило жодного голого npx; дисципліна рецензування, механічного контролю немає |
| Блокування при збої на старому npm | Мінімальна версія npm зі строгою перевіркою рушія |
| Перевірка замість довіри | Перевірки чистого робочого дерева завершують збірку збоєм; попередження postinstall при локальних перезаписах блокування |
Попередні спроби
- Стандартна заборона запуску скриптів життєвого циклу — це напрямок екосистеми:
- Періоди охолодження випусків — усталена практика:
- pnpm стандартно відкладає випуски, молодші на день.
- Значення 3 дні відповідає давній домовленості Renovate
minimumReleaseAge.
- Набір заходів відповідає усталеним рекомендаціям фреймворків:
- Таксономія атак TUF: атаки довільного встановлення програмного забезпечення, «mix-and-match» та зайвих залежностей.
- Посібник OpenSSF з npm: точні щодо блокування CI-встановлення.