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