SAST-аналіз із Semgrep: налаштування CI/CD, кастомні правила, тріаж

Перевірки коду на вразливості часто тонуть у хибних спрацюваннях, і команда перестає їм довіряти. Ми налаштовуємо Semgrep під ваш репозиторій: правила, режими запуску та порядок розбору знахідок. Частка хибних спрацювань падає, а час перевірки скорочується в рази.
Часті запитання

Semgrep налаштування: чому аналіз коду не ловить уразливості

Типова картина: Semgrep налаштування формально виконано — запуск у конвеєрі збірки є, звіт надходить, а користі з нього майже немає. Або спрацьовує все підряд, включно з фікстурами та прикладами з документації, або правил настільки мало, що вони мовчать на реальних проблемах. Команда швидко починає вважати такі перевірки формальністю.

Перший корінь — сам набір правил. Готові конфігурації не знають ваших домовленостей: як поводитеся з секретами, які обгортки над запитами використовуєте, де взагалі допустиме недовірене введення.

Правила аналізатора дають шум саме там, де контекст проєкту не враховано, і автор правки привчається закривати знахідку не читаючи.

Другий корінь — пороги та розбір спрацьовувань. Якщо кожне зауваження блокує збірку, у конфігурації з'являються винятки; якщо не блокує нічого, перевірки коду ігнорують.

Робоча схема — падати на нових знахідках у змінених рядках і тримати накопичений борг окремою чергою з зрозумілим власником.

Третій корінь — місце перевірки в процесі. Коли аналіз безпеки в конвеєрі збірки запускається тільки на головній гілці або раз на добу, зворотний зв'язок надходить через години після правки і вже не пов'язується з нею в голові автора. Статичний аналіз коду не працює не через слабкий інструмент, а через запуск для галочки.

Далі розбираємо, як це закривається крок за кроком: розмежування правил за зонами відповідальності, пороги на змінах, регулярний розбір знахідок і супровід конфігурації в актуальному стані.

Швидкість перевірок, шум у звітах, покриття правил

Повний прогін Semgrep по всій історії репозиторію триває десятки хвилин — і цю ціну розробник платить на кожній перевірці змін.

Ми налаштовуємо аналіз лише за зміненим кодом: скануються порушені та залежні файли, правила беруться з кешу, прогін стоїть обов'язковим кроком до злиття гілки. Перевірка змін займає пару хвилин і не вибиває інженера з контексту задачі.

Шум — головна причина, через яку команди вимикають сканер. Частка хибних спрацьовувань падає від конфігурації, а не від «магії»: точні шаблони замість широких виразів, явні пороги серйозності для блокуючих рівнів, винятки для генерованого коду та тестових даних.

Окремо ведемо базову лінію знахідок: збірка падає лише на нових дефектах, а успадковані йдуть у беклог з відповідальним.

Публічний набір правил закриває типові шаблони, але не знає про внутрішні бібліотеки та самописні обгортки доступу до даних.

Тому пишемо свої правила: обов'язкові перевірки прав перед запитом, функції очищення вхідних даних, заборона на складання запитів із користувацького введення. Покриття правил аналізу зростає від стандартного профілю до карти «який клас дефектів і де саме ми ловимо».

Ефект рахуємо за потоком знахідок: скільки підтверджено, скільки відхилено як хибні, які класи дефектів не доходять до релізу.

Ін'єкції в запити, небезпечна десеріалізація, ключі та токени, зашиті в код, перестають випливати на тестуванні на проникнення — вони блокуються під час злиття.

Режими сканування: конвеєр збірки, локальний запуск, розклад

Режими різняться не набором правил, а точкою запуску та обсягом перевірюваного коду. Одні й ті самі правила дають різний час відгуку та різне охоплення залежно від того, скануємо ми весь репозиторій чи лише дельту. Нижче — чим обмежений кожен варіант і на якому ешелоні він доречний.

Режим Коли доречний Чим обмежений
Повний скан гілки в конвеєрі збірки Захищені гілки та запити на злиття в основну Час зростає з обсягом репозиторію: на великому монорепозиторії це десятки хвилин, тому тримаємо його лише на ключових гілках
Перевірка лише змінених файлів Кожен коміт у робочих гілках Не бачить проблем у коді, який не змінювався, і потребує коректної бази порівняння під час переписування історії
Локальна перевірка перед надсиланням Хук перед комітом і ручний прогін перед надсиланням змін Залежить від дисципліни та версії правил на машині розробника: розходження із сервером і обхід перевірки
Запуск за розкладом Нічний повний прогін основної та довгоживучих гілок Звіт надходить із затримкою і не блокує злиття; потрібен канал доставки та регулярний тріаж знахідок

Ці режими не конкурують, а складаються в ешелони: швидкий відгук локально, блокуюча перевірка змін у конвеєрі, регулярний повний прогін за розкладом. Розробник отримує зворотний зв'язок до надсилання коду, а інфраструктура — гарантію, що покриття не деградує.

Перехід між режимами — правка однієї конфігурації, а не переписування правил: набір і пороги спрацьовувань залишаються спільними.

Semgrep налаштування: порядок робіт від аудиту до передачі

Порядок робіт будуємо так, щоб аналіз почав приносити користь до того, як стане обов'язковим кроком збірки. Спочатку інвентаризація та запуск у м'якому режимі, і лише після розбору знахідок правило переводиться в блокуюче. Інакше команда отримує сотні спрацьовувань першого ж дня і перестає дивитися на звіт взагалі.

  1. Аудит поточних правил. Вивантажуємо, що підключено зараз: які набори активні, що реально спрацьовує, що дублює лінтери та форматтери, які перевірки шумлять на легітимному коді.
  2. Схема запуску аналізу. Визначаємо точки входу — на кожній зміні, за розкладом на основній гілці, перед випуском версії — і що кешується між запусками, щоб розбір не подовжував збірку.
  3. Налаштування під проєкт. Вимикаємо шумні перевірки, піднімаємо пороги значущості, пишемо частину правил під внутрішні домовленості: робота із секретами, розбір вхідних даних, звернення до зовнішніх сервісів.
  4. Перевірка на історії змін. Проганяємо конфігурацію по минулих правках, а не лише по свіжому коду: так видно реальний обсяг знахідок і те, які правила дають хибні спрацьовування на вашій кодовій базі.
  5. Режим попереджень замість блокування. Перші проходи нічого не зупиняють: звіт збирається, знахідки розбираються, лічильник хибних спрацьовувань іде вниз. Блокування вмикається, коли частка достовірних знахідок це виправдовує.
  6. Регламент тріажу. Домовляємося, хто і в який строк дивиться звіт, як позначається хибне спрацьовування і як правило потрапляє у винятки — з обґрунтуванням, а не мовчки.
  7. Передача. Правила лежать у репозиторії поруч із кодом, схема запуску описана, у команди є порядок правки та зрозуміла точка входу.

Артефакти: конфігурації правил, схеми, регламент розбору знахідок

Після завершення робіт у репозиторії залишається не разове налаштування, а робочий контур аналізу, який команда замовника розвиває без нас. Усі артефакти версіонуються разом із кодом і проходять рев'ю як звичайні зміни — тоді видно, хто і навіщо правив перевірки.

  • Набори власних правил під наш стек, розбиті за мовами та зонами відповідальності: обов'язкові для злиття та інформаційні. Кожне правило йде з прикладом «спрацювало — що робити» і перевіркою на тестовому наборі.
  • Політика винятків і придушень: де ставиться придушення (у коді чи в конфігурації), хто погоджує, обов'язкові причина, власник і строк життя. Винятки без власника потрапляють в окремий звіт.
  • Регламент розбору знахідок: які рівні критичності блокують злиття, які йдуть у чергу, хто ухвалює рішення «виправити / придушити / прийняти ризик» і як фіксується обґрунтування.
  • Документація щодо запуску перевірок: прогін локально до коміту, звіт за гілкою, відтворення спрацьовування, тривалість повного проходу.
  • Конфігурація вбудовування в збірку: кроки, кешування залежностей, паралельні завдання, режим падіння при нових знахідках.
  • Базовий знімок поточних знахідок — увімкнення перевірок не блокує роботу команди першого ж дня.
  • Метрики контуру: частка розібраних знахідок, число хибних спрацьовувань за кожним правилом, динаміка за критичністю.

Набір передаємо з коротким навчанням: інженери замовника проганяють його самі, а ми залишаємося на зв'язку щодо розвитку правил.

Кейс: частка хибних спрацьовувань і час перевірки до та після

Початкова точка

Проєкт — монорепозиторій з десятком сервісів і спільним конвеєром, аналіз коду увімкнули на правилах за замовчуванням. Після кожної зміни звіт приносив сотні зауважень, з яких підтверджувалися одиниці: частка хибних спрацьовувань трималася на рівні 71%.

Розбір звіту перед злиттям займав у середньому 45 хвилин, інженери почали пропускати перевірки і дивитися лише на статус збірки — захист формально працював, але нічого не ловив.

Що змінили

Semgrep налаштували під структуру репозиторію, а не навпаки. Правила розбили на набори: критичні (витоки секретів, ін'єкції, небезпечна десеріалізація) блокують злиття, решта йдуть у звіт без зупинки конвеєра.

Кастомні правила описали внутрішні обгортки доступу до даних, а тестові каталоги та згенерований код винесли у винятки. Додали порівняння з базовою гілкою — перевіряються лише змінені рядки, а не файл цілком.

Результат

Частка хибних спрацьовувань упала з 71% до 9%, і звіт знову стали читати цілком, а не вибірково. Час перевірки змін скоротився з 45 хвилин до 7, при цьому жодна критична знахідка не загубилася: їх ловлять на етапі перевірки, а не на проді.

Через кілька тижнів команда перестала сперечатися про шум і зайнялася розвитком правил — новий набір під сервіс додається за один прохід.

Чим штатні правила відрізняються від власних і коли потрібні обидва

Готовий набір Semgrep закриває типові класи уразливостей: ін'єкції, слабку криптографію, секрети в репозиторії, небезпечні виклики популярних бібліотек. Знахідки з'являються з першого прогону — правила спираються на загальні сигнатури мови, а не на структуру вашого коду.

Власні правила під проєкт описують специфіку архітектури: обов'язковий виклик обгортки замість прямого запиту до бази, перевірку прав в обробнику, заборону на внутрішній модуль із відомою слабкістю. Вони прив'язані до імен ваших сутностей, тому чужий проєкт їх не підхопить.

Набір Коли підходить Обмеження
Штатний Перший прогін, зовнішні залежності, типові помилки Не бачить внутрішніх домовленостей, шумить на безпечних для вас конструкціях
Власний Свій шар доступу до даних, обов'язкові перевірки прав Потребує супроводу: після рефакторингу шаблони треба переперевіряти
Обидва разом Продукт із власною архітектурою та зовнішніми залежностями Потрібна пріоритизація, інакше потік знахідок змішується і розбір розтягується

Суміщення наборів дає повну картину: штатний закриває зовнішній контур, власний — внутрішні домовленості команди.

Пріоритизація йде за джерелом знахідки: спрацьовування свого правила майже завжди означає порушення вашої ж домовленості про код, тоді як попередження штатного частіше потребує перевірки контексту.

Межа проходить за простим питанням: чи спрацює правило в незнайомому проєкті тією ж мовою? Якщо так — це штатний набір; якщо воно спирається на ваші модулі — власний. Обидва разом закривають і загальний фон, і специфіку архітектури проєкту.

Обмеження та типові питання перед впровадженням

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

Тому перевірки вбудовуємо як один із шарів — поруч із контролем залежностей і пошуком секретів. Нижче — сумніви, які команда замовника піднімає найчастіше до старту робіт.

Окрема тема — супровід. Свої правила в Semgrep живуть як код: у них є власник, тести на прикладах спрацьовувань і прогін при оновленні движка. Без цього через пару місяців набір перетворюється на звалище, яке вимикають цілком — разом із корисними перевірками.

Хибні спрацьовування паралізують роботу команди?

Знімаємо три причини шуму: будуємо базову лінію за поточним станом репозиторію і не блокуємо те, що було раніше; вмикаємо перевірку лише на змінених рядках; задаємо поріг за рівнем критичності для блокування, решта йде у звіт.

Придушення оформлюємо анотацією з обґрунтуванням і строком перегляду. Частку хибних спрацьовувань рахуємо на тижневих тріаж-сесіях — це вимірювана величина, а не відчуття.

Що буде при оновленні правил або движка?

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

Чи можна впроваджувати поетапно, без зупинки релізів?

Так, і це бажаний шлях: один-два сервіси в режимі спостереження, потім блокування на змінених рядках, потім розширення на решту репозиторіїв. Порядок етапів фіксуємо заздалегідь, щоб команда бачила, коли перевірки почнуть впливати на збірку, і встигла розібрати накопичене.

З чого почнемо роботу за вашим репозиторієм

Щоб старт робіт за репозиторієм займав дні, а не тижні, нам потрібен від вас мінімальний набір вхідних даних і одна коротка розмова по суті. Список нижче — те, що запитуємо на обговоренні задачі; він же стає каркасом плану впровадження перевірок.

  • Доступ до коду: репозиторій або його дзеркало з історією комітів — без неї не побудувати базовий зріз і не відокремити нові знахідки від тих, що живуть у кодовій базі давно. Для монорепозиторію — розбивка за каталогами та власниками модулів.
  • Доступи до систем збірки: право завести окремого сервісного користувача і додати крок аналізу, але без прав на зміну логіки релізів.
  • Точки інтеграції: що має запускати перевірку — коміт, запит на злиття, нічний прогін за повною історією. Від цього залежить, де ставимо блокуючі пороги, а де лише звіт.
  • Чинні правила та винятки: які лінтери й аналізатори вже працюють, де зберігаються придушення, хто їх погоджує. Дублювати наявні перевірки сенсу немає.
  • Пріоритети за класами знахідок: які категорії для вас критичні, що йде в ігнор (тести, згенерований код, сторонні вендорські каталоги). Це прямо впливає на обсяг кастомних правил.
  • Відповідальний за тріаж з боку замовника: один інженер, який розбирає знахідки і вирішує, що йде в роботу, а що у виняток.

Після цього ми повертаємося з оцінкою та планом: етапи, обсяг кастомних правил для Semgrep, цільовий рівень шуму та метрики, за якими будемо перевіряти результат. Опишіть задачу — почнемо з розбору репозиторію.

Наші компетенції:

Останні роботи

  • Розробка сайту компанії B2B ADVANCE
    Розробка сайту компанії B2B ADVANCE
    1542
  • Розробка веб-додатків для компанії FEEDME
    Розробка веб-додатків для компанії FEEDME
    1393
  • Розробка веб-сайту для компанії БЕЛФІНГРУП
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    1081
  • Розробка інтернет магазину для компанії FURNORO
    Розробка інтернет магазину для компанії FURNORO
    1368
  • Розробка логотипу компанії B2B Advance
    Розробка логотипу компанії B2B Advance
    815
  • Розробка веб-додатків для компанії Enviok
    Розробка веб-додатків для компанії Enviok
    1139