Security misconfiguration і розкриття даних
Зміст
Більшість глав розділу — про дефект у коді. Ця про клас, у якому коду можна не чіпати взагалі: застосунок написано правильно, тести зелені, а уже є — увімкнений дефолт, зайвий сервіс, надто балакуча сторінка помилки. Знайти таке дешево: воно видно з відповіді сервера й з налаштувань стенду. Парадокс у тому, що дешеві знахідки й лишаються незнайденими найчастіше — у релізному чеклисті їх зазвичай немає, бо «це ж не код».
Для QA тема ближча, ніж здається: за каноном тестове середовище — це та сама конфігурація, тільки з іншими обліковими даними. Глава є каноном теми на сайті, тож межі варто назвати одразу: — глава HTTP-заголовки безпеки, CSP і клікджекінг, зовнішні сутності XML — SSRF, завантаження файлів і XXE, шифрування й TLS — Криптографія і транспорт для QA, гігієна секретів у — Секрети та конфігурація в CI.
Хибна конфігурація: вразливість без дефекту в коді
(security misconfiguration) — це коли систему, застосунок або хмарний сервіс налаштовано неправильно з погляду безпеки, і саме це створює вразливість. Варте уваги те, чого в означенні немає: жодної згадки про помилку програміста.
У редакції :2025 категорія стоїть другою — піднялася з пʼятого місця попередньої редакції, бо в даних цього циклу хибних конфігурацій більше. Поруч цифра, що пояснює вагу теми краще за аргументи: 100% протестованих застосунків мали ту чи іншу форму хибної конфігурації, із середньою частотою 3,00% і понад 719 тисячами входжень . Провідні слабкості — CWE-16 (Configuration) і CWE-611 (некоректне обмеження зовнішньої XML-сутності).
Ознаки категорії названо поіменно, і кожна читається як пункт перевірки:
- відсутній (hardening) будь-якої частини стеку або неправильно налаштовані дозволи на хмарних сервісах;
- увімкнені чи встановлені зайві можливості — непотрібні порти, служби, сторінки, акаунти, тестові фреймворки або привілеї;
- дефолтні акаунти з незміненими паролями лишаються ввімкненими;
- обробка помилок віддає користувачеві або інші надто інформативні повідомлення;
- сервер не надсилає заголовків і директив безпеки або їхні значення небезпечні.
Серед сценаріїв джерело наводить показово буденний: (directory listing) не вимкнено на сервері — просто перелічує директорії.
Запобігання сформульовано як процес: відтворюваний процес харденінгу, що дає швидко підняти ще одне належно закрите середовище; dev, QA і prod налаштовані однаково, але з різними обліковими даними; автоматизована перевірка конфігурацій в усіх середовищах, а без автоматизації — щонайменше ручна щороку. Дзеркальним випадком названо поіменно й тестові фреймворки в проді.
«Небезпечний дефолт» тут не метафора, а стан із коробки, ще й версійний: у більшості XML-парсерів Java обробку зовнішніх сутностей увімкнено за замовчуванням, а PHP 8.0+ із дефолтним парсером блокує таку атаку сам. Відповідь на «чи вразливі ми» залежить від версії рантайму, а не від вашого коду.
Конфігурація середовища: одинадцять тестів, а не примітка
Конфігурацію середовища легко вважати нічиєю темою: вона виглядає розлитою по інших перевірках. У вона не розлита — (Configuration and Deployment Management Testing) стоїть другою групою тестів усередині «Web Application Security Testing», з власною нумерацією і рівно одинадцятьма пунктами. Це вже готовий чекліст стенду:
| № | Тест WSTG | Предмет |
|---|---|---|
| 4.2.1 | Test Network Infrastructure Configuration | елементи середовища |
| 4.2.2 | Test Application Platform Configuration | дефолти й залишки інсталяції |
| 4.2.3 | Test File Extensions Handling for Sensitive Information | що віддається як текст |
| 4.2.4 | Review Old Backup and Unreferenced Files for Sensitive Information | старі копії, лістинг |
| 4.2.5 | Enumerate Infrastructure and Application Admin Interfaces | адмінки й дефолтні креденшели |
| 4.2.6 | Test HTTP Methods | службові дієслова |
| 4.2.7 | Test HTTP Strict Transport Security | HSTS — глава 8 |
| 4.2.8 | Test RIA Cross Domain Policy | файл політики в корені |
| 4.2.9 | Test File Permission | права на конфіги й логи |
| 4.2.10 | Test for Subdomain Takeover | мертвий DNS-запис |
| 4.2.11 | Test Cloud Storage | доступ до сховища |
Чекліст каже, що перевіряти, і не каже, яким має бути правильне значення: друге звіряють із базовими лініями або бенчмарками конфігурації (CIS-CAT Lite, Microsoft Attack Surface Analyzer, NIST National Checklist Program), причому рекомендована конфігурація різниться залежно від політики сайту й функціональності серверного ПЗ. Найдешевший артефакт теми — перелік визначених портів, потрібних застосунку, який слід вести й тримати під контролем змін: без нього критерію «зайвий порт» не існує.
Дві межі варто знати заздалегідь. Перша: досить однієї вразливості, щоб підірвати безпеку всієї інфраструктури, і навіть дрібні та на позір неважливі проблеми можуть перерости в серйозні для іншого застосунку на тому самому сервері — радіус ураження з межами застосунку не збігається. Друга: «сканер зелений» звітом про конфігурацію не є — інструменти, що судять за версією сервера, дають і хибнопозитивні, і хибнонегативні результати, а саме сканування знаходить лише вразливості виставлених елементів, не бачачи бекендів автентифікації, бази чи реверс-.
Дефолт платформи й залишки інсталяції
Чому дефолт узагалі небезпечний, джерело формулює так, що знімає моралізаторство: багато різних систем зазвичай постачаються з узагальненими конфігураціями, які можуть не пасувати до завдання, що вони виконуватимуть на конкретному сайті, де їх встановлено. (application platform configuration) небезпечна не тому, що погана, а тому, що її складали без знання про ваш випадок. Тому в ревʼю дивляться, чи ввімкнено лише ті серверні модулі, які потрібні застосунку — вимкнений модуль зменшує й заразом знімає вплив вразливостей, які можуть зʼявитися в ПЗ вендора пізніше, якщо вони є лише у вже вимкнених модулях, — чи стоять власні сторінки помилок замість дефолтних і чи працює серверне ПЗ з мінімізованими привілеями. Окремий дефолт видно лише в доці платформи: файли machine.config і кореневий web.config .NET Framework за замовчуванням може читати будь-який користувач.
Друга половина теми — (sample and known files and directories): типова інсталяція містить приклади застосунків, документацію й тестові сторінки, і все неістотне слід прибрати перед розгортанням, щоб уникнути післяінсталяційної експлуатації — саме перед, а не після знахідки. Ризик підперто чотирма реальними , у кожній з яких вразливість принесла демо-складова інсталяції, а не код застосунку. Поруч стоять ще дві перевірки того самого релізного чекліста: підтвердити, що в продакшн-середовищах не лишилося дебаг-коду чи розширень, і переглянути коментарі всередині HTML, які можуть розкрити внутрішню інформацію — інколи в коментар потрапляє й сам вихідний код. Сканер відомих файлів пошук прискорює, але єдиний спосіб бути справді впевненим — повний перегляд умісту сервера з рішенням щодо кожного файлу, чи стосується він самого застосунку.
Адмінка: знайти її дешевше, ніж здається
(administrator interface) дає певним користувачам виконувати привілейовані дії на сайті, і стан справ джерело описує без помʼякшень: у багатьох випадках такі інтерфейси не мають достатніх контролів, щоб захистити їх від неавторизованого доступу. Ціль тесту — виявити приховані адміністративні інтерфейси й функціональність, тобто прихованість інтерфейс з-під перевірки не виводить. Каналів пошуку кілька, і жоден не потребує експлойта: спроба вгадати шлях може бути такою простою, як запит /admin чи /administrator, а в деяких сценаріях адреса розкривається за секунди пошуковими запитами (Google dorks); перебір умісту сервера словником; посилання на адміністративну функціональність у всьому надісланому клієнту коді; конфігураційна чи довідкова документація продукту, якщо сервер розгорнуто в дефолтній конфігурації; власні дефолтні адмін-сторінки чи шляхи, які може мати кожен вебфреймворк; і навіть інший порт — адміністративний інтерфейс Apache Tomcat часто буває на порту 8080.
Окремий вектор — підміна параметра: привілейовану функцію може вмикати GET- чи POST-параметр або змінна в кукі, а підказками названо приховані поля на кшталт <input type="hidden" name="admin" value="no">. І рідкісний випадок, коли джерело називає побічну шкоду самого тесту: перебір по знайденій адмінці має враховувати можливість блокування адміністративного облікового запису. Закривають її позитивною вимогою — харденінг, щоб адміністративні сторінки не були доступні всім, через IP-фільтрацію чи інші контролі, і перевірка, що жоден компонент не використовує чи конфігурацій. Слово «компонент» тут несуче: черга, кеш, база й брокер — кожен зі своїм постачальним акаунтом. Дефолтні креденшели (default credentials) і є найдешевшою атакою з усіх: якщо інтерфейс знайдено, слід звіритися з переліками дефолтних паролів, а вони публічні.
Що сервер віддає, коли його не питали
Лістинг директорій — найочевидніший спосіб, у який помилково налаштований сервер розкриває несилані сторінки. Процедура в один рядок: запитати всі перелічені каталоги й визначити ті, що віддають лістинг; сканери ще й окремо повідомляють про кожен вебкаталог, який дозволяє індексацію. Наслідок не в самому переліку: бекап зазвичай не потрапляє в індекс пошуковика, бо на нього ніхто не посилається, — але якщо він лежить у каталозі з увімкненим переглядом, пошуковик про нього дізнається.
(unreferenced files) лежать на сервері й досяжні за адресою, хоча застосунок на них не посилається; натрапити на них і дістати важливе про інфраструктуру або облікові дані — не рідкість. Механізм витоку джерело пояснює прикладом: копія login.asp під іменем login.asp.old дозволяє качати вихідний код, бо login.asp.old типово віддається як текст, а не виконується — через своє розширення. Беруться копії з передбачуваних місць: редактори лишають file~, руки — file.old, файлова система — снапшоти, а правку файлів по місцю на файловій системі вебсервера джерело окремо називає особливо поганою звичкою, бо саме вона їх і породжує. Дістають із них облікові дані до бази в include-файлах, несилану адміністративну сторінку, яку відкриє будь-хто, хто знає, де її шукати, і стару версію з вразливістю, полагодженою у свіжішій, — тобто «баг полагоджено» і «вразливість недосяжна» це різні стани. Лікування системне: належні політики керування конфігурацією мають запобігати появі застарілих і несиланих файлів.
Сусідній тест дивиться на ту саму механіку з іншого боку. (file extension) — те, за чим вебсервер визначає, які технології, мови й плагіни треба задіяти, щоб виконати запит, тож воно й розкриває стек; канонічний приклад витоку — файл connection.inc, пряме звернення до якого віддає його вміст. Класів два: ті, які вебсервер не має віддавати ніколи (.asa, .inc, .config), і ті, які перевіряють на те, чи вони справді мають віддаватися, а не є залишками — архіви, .java, .txt, .bak, .old. Перевірка робиться покаталожно, а саме лише розширення може бути оманливим і не є остаточним доказом.
Доступ, який ніхто не обирав: права на файли й хмарне сховище
Дефект тут формулюється не як «секрет лежить не там», а як ширші за потрібні (file permissions): коли ресурсу задано налаштування прав, що дає доступ ширшому діапазону , ніж потрібно, це може призвести до розкриття чутливої інформації або до зміни цього ресурсу ненавмисними сторонами. Найпоказовіший випадок — знову дефолт: значення токена для доступу до API може зберігатися в конфігураційному файлі, права на який після встановлення за замовчуванням виставлені на читання для всіх. Модель ширша за інсайдера — дані дістає й віддалений атакувальник, який скомпрометував сервіс іншими вразливостями, але отримав лише привілей звичайного користувача, тож і перевіряють від імені непривілейованого акаунта: конфігураційні файли, ключі й паролі, лог-файли, виконувані файли, тимчасові файли й каталог завантажень. Інструмент навмисно тривіальний: у Linux права перевіряють командою ls, а namei дозволяє перелічити їх рекурсивно; класифікатор — CWE-732.
Хмарне сховище дає той самий клас із іншим , і починати варто з розвіювання ходової тези. (cloud storage misconfiguration) — це саме конфігурація, а не заводська настройка: за замовчуванням усі S3 приватні й доступні лише користувачам, яким доступ надано явно, а публічний доступ видається вручну — і на сам бакет, і на окремі обʼєкти в ньому, тож «бакет закритий» вердиктом про всі файли не є. Наслідком названо три різні знахідки — розкриття чутливої інформації, підміну даних, несанкціонований доступ. Процедура читається як звичайний негативний тест API: спершу визначити URL, за яким сервіс віддає дані, і тоді прочитати неавторизовані дані та залити новий довільний файл, причому для тестів можна взяти curl. Критерій проходження названо дослівно: правильно закритий бакет відповідає на спробу заливання помилкою AccessDenied на операції PutObject.
Периметр без коду: піддомен, метод, файл політики
(subdomain takeover) — вразливість, успішна експлуатація якої дозволяє супротивнику заявити права на піддомен жертви й перебрати контроль над ним. Ані код, ані сервери жертви не чіпають: потрібні дві умови разом — запис піддомену вказує на неіснуючий або неактивний ресурс чи зовнішній сервіс, і провайдер, який хостить цей ресурс, неналежно перевіряє володіння піддоменом. Уразливий не лише CNAME: перелічено A, CNAME, MX, NS, TXT та інші, і найважчий випадок саме NS — захоплення через NS-запис має найвищий вплив, бо може дати повний контроль над усією DNS-зоною й доменом жертви. Перевірка виглядає як інвентаризація: перелічити всі можливі домени — і колишні, і чинні — та виявити забуті чи неправильно налаштовані; явна ознака — коли піддомен повертає «404 — File not found», і це чітка вказівка на вразливість. Лікування — прибрати вразливий запис із зони. Механіка записів — глава DNS, IP, порти та мережа.
Наступний пункт чекліста — методи: деякі з менш відомих методів HTTP можна вжити для лихих цілей, якщо вебсервер налаштовано хибно, а сліпа зона виникає тому, що більшості застосунків потрібні лише GET і POST, тож решту рідко враховують. Через увімкнений PUT атакувальник може покласти в систему довільний і потенційно шкідливий вміст, що веде до віддаленого виконання коду, дефейсу сайту або в обслуговуванні. OPTIONS тут вхідна точка, а не вердикт — відповідь сервера перевіряють, надсилаючи запити різними методами, зокрема довільно вигаданими на кшталт BILBAO, FOOBAR, CATS: вони показують, чи не побудований фільтр на переліку відомих дієслів. Окремо перевіряють підміну методу заголовком (X-HTTP-Method, X-HTTP-Method-Override, X-Method-Override) — інший код відповіді означає, що заборона методу на периметрі забороною не є. Історичний TRACE подано з межею, яку ставить саме джерело: у сучасних браузерах атаку можна провести лише тоді, коли застосунок інтегрується з технологіями на кшталт Flash, тож увімкнений TRACE читається як гігієна конфігурації, а не як живий експлойт. Семантика методів — глава HTTP-методи, структура, заголовки.
Останній пункт ряду — (cross-domain policy file), який описує дозволи, з якими вебклієнт може звертатися до даних на іншому домені. Це не код застосунку: головні файли політики лежать у корені домену, і клієнт завжди спершу перевіряє головний, тож і перевірка починається звідти — спробувати отримати crossdomain.xml і clientaccesspolicy.xml із кореня застосунку і з кожної знайденої теки. Ціна помилки названа поруч: погана конфігурація таких файлів уможливлює атаки Cross-site Request Forgery і може дозволити третім сторонам дістатися чутливих даних, призначених користувачеві. Критерій оцінки вузький: запити мають надходити лише з тих доменів, портів або протоколів, які потрібні, надто дозвільних політик уникають, а політики із зірочкою розглядають особливо уважно — канонічний приклад помилки з керівництва це <allow-access-from domain="*" />.
Помилка як розвідка
Атака рідко починається з експлойта — вона починається з фази розвідки, у якій збирають технічні дані про ціль: назви й версії сервера застосунку, фреймворків, бібліотек.
Приклади витоку джерело дає буквальні: версії Struts2 і Tomcat, розкриті винятком, відрендереним користувачеві; рядок «note: The full stack trace of the root cause is available in the Apache Tomcat/7.0.56 logs»; помилка SQL-запиту разом зі шляхом установлення сайту — саме її подано як таку, що дає визначити точку .
Редакція 2025 винесла цей клас в окрему нову категорію — A10 Mishandling of Exceptional Conditions (). Вона містить 24 CWE, серед провідних слабкостей названо CWE-209 (повідомлення про помилку з чутливою інформацією) і CWE-636 (небезпечне падіння у відкритий стан, failing open), а наслідки описано через конфіденційність, доступність і цілісність. Критерій перевірюваний: щойно застосунок не впевнений щодо своєї наступної інструкції — нештатну умову оброблено неправильно. Серед названих сценаріїв — системна помилка бази даних, показана користувачу, після якої атакувальник навмисно провокує помилки, щоб зібрати системну інформацію для точнішої , і вичерпання ресурсів, коли застосунок ловить винятки під час завантаження файлів, але не звільняє ресурси.
Цільова поведінка сформульована парою, і саме пара є одиницею перевірки: узагальнена відповідь користувачеві, деталі — у серверний лог.
Звідси конкретика: перекрити всі можливі режими відмови й уживати 5xx лише для запитів, які застосунок не може виконати, не даючи у відповіді вмісту, що розкриває деталі реалізації. 4xx — для запитів, що впали через помилку на боці HTTP-клієнта; 5xx — через непередбачений баг на сервері, і їх треба моніторити, бо вони добре вказують, на яких наборах даних застосунок валиться.
Одна межа рятує від хибної цитати на співбесіді: шпаргалка Error Handling окремої вимоги «не показувати стек-трейс» не формулює — у ній заборонено віддавати вміст, що розкриває деталі реалізації. Стек- користувачеві названо ознакою вразливості в A02, а іменованою слабкістю — CWE-209 у A10.
Запобігання A10 стисле: ловити системну помилку там, де вона виникає, плюс глобальний обробник на випадок пропущеного; обірвану відкотити цілком і почати наново (це і є failing closed); додавати ліміти — rate limiting, квоти, ; тримати обробку в одному місці.
Перевірка з боку автотестів буденна: помилку провокують навмисно, а дивляться не на текст, а на склад відповіді.
// Playwright: відповідь про помилку не несе деталей реалізації
const res = await request.post('/api/orders', { data: { qty: -1 } });
expect(res.status()).toBeGreaterThanOrEqual(400);
const body = await res.text();
for (const marker of ['at com.', 'Traceback', 'Exception in', '/var/www/', 'SQLSTATE']) {
expect(body).not.toContain(marker);
}
Лог: засіб захисту, який сам є ціллю
Логи звикли вважати інструментом розслідування. Джерело заходить з іншого боку: механізми логування й зібрані дані подій мусять бути захищені від підміни в передачі, неавторизованого доступу, модифікації й видалення після збереження — бо логи можуть містити персональні й інші чутливі дані, а також відомості про код і логіку застосунку. Звідси головне: лог може бути ціллю атаки саме через свою корисність як засобу захисту.
| Що атакують | Як це виглядає |
|---|---|
| Конфіденційність | Неавторизований доступ до чутливого в логах: персональні дані стають плацдармом для атак на цих користувачів, технічні секрети на кшталт паролів — для глибшої атаки |
| Доступність | Атакувальник заливає лог-файли, щоб вичерпати місце на диску під подальше логування |
| Підзвітність | Атакувальник спричиняє запис хибної ідентичності, щоб приховати відповідальну сторону |
Друга й третя цікаві тим, що застосунку нічого не робиться: вимкнено засіб виявлення, а не сервіс.
Вимоги до самого логу перевіряються запитом або переглядом прав. У вебзастосунках логи не мають бути виставлені у вебдоступних місцях; якщо вже так сталося — з обмеженим доступом і з MIME-типом plain text, а не HTML. Право читати дані логів обмежують і періодично переглядають — «доступ є в усіх, хто має доступ до сервера» це невиконана вимога, а не опис норми. І відмови самої підсистеми логування не мають ні заважати роботі застосунку, ні відкривати витік: зламаний логер це два дефекти одразу, і другий помітно менш очевидний.
Окремий сюжет — (log injection). Дані події санітизують перед записом, щоб їй запобігти: зокрема символи повернення каретки (CR), переводу рядка (LF) і символи-розділювачі. Перевірка дешева: вкласти CR/LF і розділювач у поле, яке точно логується (логін, User-Agent), і подивитися, чи зʼявився в лозі підроблений другий рядок. І ще одне, що рідко спадає на думку: саме логування джерело перевіряє як вектор відмови в обслуговуванні — його не має бути можливо використати для вичерпання ресурсів, як-от заповненням диска або перевищенням місця під журнал транзакцій бази даних.
Персональні дані: перелік, а не інтуїція
Питання «чи можна це писати в лог» зазвичай вирішують на око. Джерело дає два класи даних, і різниця між ними операційна.
Клас 1 — не пишеться в лог напряму, його «прибирають, маскують, санітизують, хешують або шифрують»: код застосунку; значення ідентифікації сесії (якщо потрібне відстеження — замінити хешованим); токени доступу; чутливі персональні дані й деякі форми PII, наприклад дані про здоровʼя, державні ідентифікатори, вразливі особи; паролі автентифікації; рядки підключення до бази даних; ключі шифрування та інші первинні секрети; дані банківського рахунку чи власника платіжної картки.
Клас 2 — корисне для розслідування, але потребує особливого поводження перед записом: шляхи файлів, внутрішні імена й адреси мережі, нечутливі персональні дані — імена людей, телефони, адреси електронної пошти. Тобто «це ж просто імʼя» аргументом за запис як є не працює.
У першому класі стоять паролі, токени й ключі — і це інше питання, ніж маскування секретів у пайплайні: там ідеться про логи , а тут про те, чи ці значення взагалі писали в лог застосунку.
Далі те, що в QA-практиці згадують рідко: запис сам є обробкою. Не логувати дані, якщо це не санкціоновано законом: перехоплення частини комунікацій, стеження за працівниками й збір деяких даних без згоди можуть бути незаконними. Так само не пишуться дані, від збору яких користувач відмовився або чия згода вичерпалася. А якщо особа для розбору не потрібна або ризик завеликий, застосовують (de-identification): видалення, перемішування (scrambling) або прямих і непрямих ідентифікаторів. Критерій вибору джерельний: не «як зручніше», а чи потрібна ідентичність для мети. Той самий критерій працює й у — глава Тест-дані: фабрики, фікстури, ізоляція.
Витікають персональні дані не лише через лог. Показова механіка — IP-адреса через сторонній контент: якщо в застосунку можна вбудувати картинку із зовнішнього домену (аватар, підпис, вкладене фото), зловмисник розміщує її на своєму домені й дивиться на HTTP-запити за нею, щоб дізнатися справжню IP-адресу жертви. Та сама проблема існує в HTML-листах — і саме тому більшість поштових клієнтів блокує завантаження стороннього контенту за замовчуванням. Висновок простий: зовнішній ресурс у стрічці користувача — це перевірка приватності, а не продуктивності.
І остання вимога, яку зазвичай не вважають перевірюваною: якщо застосунок не може запобігти зловживанню чи розкриттю чутливої інформації — зокрема логів, — правду треба сказати користувачам у ясній зрозумілій формі, щоб вони зробили поінформований вибір.
Дефолти середовища: контейнер, порт, сокет
«У нас у контейнері» саме собою не є ні аргументом безпеки, ні дефектом: за правильного використання контейнеризація може підвищити безпеку порівняно із запуском застосунків прямо на хості, проте певні хибні конфігурації знижують рівень безпеки або вносять нові вразливості. І варто прибрати «контейнер це маленька віртуалка»: ділять ядро хоста, тож якщо ядро хоста вразливе — вразливі й контейнери. Що таке образ і контейнер — глава Docker і тестові середовища.
Стани з коробки, які доводиться міняти явно, джерело називає поіменно:
- користувач — контейнер за замовчуванням працює від root, і непривілейований користувач названо найкращим способом запобігти ;
- можливості ядра —
--privilegedдодає контейнеру ВСІ можливості ядра Linux; найбезпечніше скинути всі (--cap-drop all) і додати назад лише потрібні; - привілеї всередині —
--security-opt=no-new-privilegesзакриває їх здобуття черезsetuid/setgid-бінарники; - мережа між контейнерами — inter-container connectivity (
icc) увімкнено за замовчуванням, тож усі контейнери спілкуються через мостову мережуdocker0; - профіль безпеки — дефолтний профіль (seccomp, AppArmor чи SELinux) не вимикають, а беруть за базову лінію;
- файлова система —
--read-only, а під тимчасові файли--tmpfs; - ресурси — обмеження памʼяті, CPU, дескрипторів, процесів і перезапусків названо найкращим способом уникнути відмови в обслуговуванні;
- демона — поки не потрібно інакше, демон не запускають на рівні
debug.
Усі вісім є станами, а не сценаріями, тож перевіряються середовища, а не тестом. Окремо стоїть режим rootless: демон і контейнери під непривілейованим користувачем означають, що навіть вирвавшись із контейнера, атакувальник не отримає прав root на хості.
Два місця заслуговують на увагу окремо. Перше — сокет демона: /var/run/docker.sock є первинною точкою входу в Docker API, власник його root, тож дати комусь доступ до сокета рівносильно наданню необмеженого root-доступу до хоста. Правило звучить як «не виставляти сокет навіть контейнерам», а монтування «лише для читання» рішенням не є — воно тільки ускладнює експлуатацію.
Друге — опублікований порт. Поширена хибна впевненість, що правила фаєрвола захищають увесь вхідний трафік, включно з призначеним контейнерам. Насправді Docker керує власними правилами iptables і nftables напряму й обходить UFW цілком: публікація порту вставляє правила, які відкривають його на всіх інтерфейсах і для всіх адрес-джерел, і ці правила зазвичай приймаються раніше, ніж застосовуються явні DENY.
Останнє — про секрети. Docker Secrets дає спосіб зберігати паролі, токени й SSH-ключі так, щоб уникнути їх розкриття в образах контейнерів або в командах запуску; межу ставить сама шпаргалка, і це її слова про сусідню платформу: для Kubernetes підхід не рекомендується, бо там секрети за замовчуванням зберігаються відкритим текстом. А звіти сканерів контейнерів варто читати уважно: вони виявляють три різні класи знахідок — відомі вразливості, секрети й хибні конфігурації в образах, — тож «сканер зелений» без уточнення класу не означає нічого.
Типові помилки
«Це не код — значить, не наш дефект». Виглядає як межа відповідальності, а насправді категорія описує рівно ту ситуацію, коли помилки в коді немає: ламає налаштування.
«Стенд налаштований інакше — це нормально». Виглядає як дрібниця, а насправді канон вимагає протилежного: середовища однакові, різняться лише обліковими даними.
«Логи пишуться — значить, із логуванням усе гаразд». Виглядає як закритий пункт, а насправді лог сам є активом: його читають, заливають до вичерпання диска й підробляють у ньому ідентичність.
«Фаєрвол закритий, порт назовні не світиться». Виглядає як доказ, а насправді Docker пише власні правила й обходить UFW. Доказом є спроба зʼєднання ззовні, а не рядок конфігурації.
«Адмінка не з інтерфейсу — на неї немає посилання». Виглядає як захід, а насправді ціль тесту WSTG — знайти саме приховані інтерфейси: шлях вгадують запитом /admin, дока продукту називає дефолтний, а фреймворк додає свій.
«Бакет відкритий за замовчуванням, це дефолт хмари». Виглядає як пояснення, а насправді джерело каже протилежне: бакети приватні, а публічний доступ хтось видав вручну — на бакет або на окремий обʼєкт.
Підсумок
- Хибна конфігурація — це вразливість без дефекту в коді. У редакції OWASP Top 10:2025 категорія стоїть другою, і 100% протестованих застосунків мали ту чи іншу її форму.
- Середовища збігаються конфігурацією й різняться обліковими даними. Ця вимога перетворює «на стенді інакше» з пояснення на знахідку.
- Помилка не кінець сценарію, а вхід у наступну атаку. Цільова поведінка — пара: узагальнено користувачеві, деталі в серверний лог; перевіряються обидві половини.
- Лог є активом і ціллю водночас. Він витікає через вебдоступне місце й зайві права — і в нього не пишуть паролів, токенів, ключів і рядків підключення.
- Дефолт — це стан, а не думка. root усередині контейнера, увімкнений
icc, опублікований повз фаєрвол порт і змонтований сокет демона лишаються там, поки їх не прибрали явно. - У конфігурації середовища є власний чекліст із одинадцяти тестів WSTG — від мережевої інфраструктури до хмарного сховища; половина знахідок цього ряду це те, що сервер віддає без запиту: лістинг каталогу,
login.asp.old,.incзамість виконання, забутий піддомен із чужим404, бакет, який приймаєPutObject.
Можливі питання
«Що таке security misconfiguration і чим вона відрізняється від звичайного бага?» Дивляться, чи розумієте ви, що дефекту в коді може не бути взагалі. Сильна відповідь називає ознаки категорії — дефолтні акаунти, зайві можливості й порти, відсутній харденінг, надто інформативні помилки, відсутні заголовки безпеки.
«Чому докладне повідомлення про помилку — це вразливість?» Очікують механізм, а не «бо негарно»: атака починається з розвідки, і версія сервера чи шлях установлення в тексті винятку є готовими розвідданими.
«Як ви перевірите, що застосунок не розкриває зайвого в помилці?» Хочуть процедуру: спровокувати помилку навмисно, дивитися на склад відповіді, звірити з серверним записом про ту саму подію й закріпити перевірку автотестом.
«Чого не можна писати в лог?» Питання-фільтр на конкретику: паролі, токени доступу, значення ідентифікації сесії, рядки підключення до бази, ключі шифрування, дані картки, чутливі персональні дані.
«На що ви подивитесь у тестовому середовищі з погляду безпеки?» Слухають, чи не почнете ви з інструментів. Сильна відповідь називає стани: від кого працює контейнер, які порти доступні ззовні, чи не змонтований сокет демона, чи збігається конфігурація стенду з бойовою.
«За яким переліком ви перевіряєте конфігурацію середовища?» Очікують не імпровізацію: у WSTG це окрема група з одинадцяти тестів — від мережевої інфраструктури до хмарного сховища, — а правильні значення для неї беруть із базових ліній і бенчмарків конфігурації.
«Як ви шукали б адмінку, якої немає в інтерфейсі?» Перевіряють, чи розумієте ви, що відсутність посилання захистом не є: ціль тесту — знайти саме приховані інтерфейси, а шлях вгадується тривіально — запит /admin, перебір словником, посилання у клієнтському коді, дефолтні шляхи фреймворка, інший порт; закриває адмінку харденінг з IP-фільтрацією і зміна дефолтних креденшелів.
«Чому старий файл login.asp.old небезпечніший за чинний?» Дивляться на розуміння механіки: копія віддається як текст, а не виконується, тож віддає вихідний код — і може містити вразливість, уже полагоджену у свіжій версії.
Джерела
Хибна конфігурація: вразливість без дефекту в коді
- OWASP Top 10:2025 — A02 Security Misconfiguration — означення категорії, пʼять ознак, сценарій із лістингом директорій, вимоги до харденінгу й однаковості середовищ, цифри охоплення, провідні CWE.
- OWASP Top 10:2025 — Introduction — перехід категорії з пʼятого місця на друге й причина підйому.
- CWE-611 — Improper Restriction of XML External Entity Reference — прописка слабкості в A02:2025.
- OWASP — XML External Entity Prevention Cheat Sheet — дефолти парсерів у Java і PHP 8.0+.
- OWASP Cheat Sheet — Docker Security — «небезпечний дефолт» як стан із коробки.
- OWASP Cheat Sheet — Error Handling — адресат надто інформативного повідомлення.
Конфігурація середовища: одинадцять тестів, а не примітка
- OWASP WSTG 4.2 — Configuration and Deployment Management Testing — склад групи з одинадцяти тестів.
- OWASP WSTG 4.2.1 — Test Network Infrastructure Configuration — перелік портів, радіус ураження, межі сканерів.
- OWASP WSTG 4.2.2 — Test Application Platform Configuration — базові лінії й бенчмарки.
Дефолт платформи й залишки інсталяції
- OWASP WSTG 4.2.2 — Test Application Platform Configuration — узагальнена конфігурація, пункти ревʼю, права на
machine.config, службові файли інсталяції й CVE, ціль про дебаг-код, коментарі в HTML, межа сканера.
Адмінка: знайти її дешевше, ніж здається
- OWASP WSTG 4.2.5 — Enumerate Infrastructure and Application Admin Interfaces — означення, канали виявлення, підміна параметра, ризик , харденінг з IP-фільтрацією, переліки дефолтних паролів.
- OWASP WSTG 4.2.1 — Test Network Infrastructure Configuration — дефолтні налаштування й креденшели в цілі тесту.
Що сервер віддає, коли його не питали
- OWASP WSTG 4.2.4 — Review Old Backup and Unreferenced Files for Sensitive Information — лістинг директорій і процедура, старих копій, що з них дістають, лікування.
- OWASP WSTG 4.2.3 — Test File Extensions Handling for Sensitive Information — роль розширення,
connection.inc, два класи, покаталожна перевірка, оманливість.
Доступ, який ніхто не обирав: права на файли й хмарне сховище
- OWASP WSTG 4.2.9 — Test File Permission — означення дефекту, дефолтні права на конфіг із токеном, перелік обʼєктів,
lsіnamei, CWE-732. - OWASP WSTG 4.2.11 — Test Cloud Storage — приватний дефолт бакета, три наслідки, процедура, критерій
AccessDeniedнаPutObject.
Периметр без коду: піддомен, метод, файл політики
- OWASP WSTG 4.2.10 — Test for Subdomain Takeover — означення, дві умови, типи записів і вплив
NS, мета тесту, ознака404, лікування. - OWASP WSTG 4.2.6 — Test HTTP Methods — рідковживані методи й хибна конфігурація,
PUT, вигадані методи, заголовки підміни, межаTRACE. - OWASP WSTG 4.2.8 — Test RIA Cross Domain Policy — означення, пріоритет кореня, наслідки поганої конфігурації, процедура, зірочка.
- OWASP Top 10:2025 — Mishandling of Exceptional Conditions — категорія й критерій «не впевнений щодо наступної інструкції», 24 CWE, CWE-209 і CWE-636, два сценарії атаки, заходи запобігання.
- OWASP Top 10:2025 — Introduction — статус A10 як нової категорії редакції 2025.
- OWASP Cheat Sheet — Error Handling — фаза розвідки, приклади витоку, пара «узагальнена відповідь / деталі в лог», семантика
4xxі5xx, межа щодо стек-трейсу.
Лог: засіб захисту, який сам є ціллю
- OWASP Cheat Sheet — Logging — захист механізмів логування, три атаки на лог, вимоги до розміщення й прав, санітизація перед записом, логування як вектор відмови в обслуговуванні.
Персональні дані: перелік, а не інтуїція
- OWASP Cheat Sheet — Logging — два класи даних поіменними переліками, правова санкція як умова запису, згода, техніки знеособлення.
- OWASP Cheat Sheet — User Privacy Protection — витік IP-адреси через сторонній контент і дефолтне блокування такого контенту, чесність перед користувачем.
Дефолти середовища: контейнер, порт, сокет
- OWASP Cheat Sheet — Docker Security — конфігурація проти технології, спільне ядро з хостом, дефолти рантайму й режим rootless, сокет демона як root-доступ до хоста, обхід фаєрвола опублікованим портом, Docker Secrets, три класи знахідок сканерів.
Що таке хибна конфігурація безпеки (security misconfiguration) і чому це вразливість без бага в коді?
Це , джерелом якої є налаштування системи, застосунку чи хмарного сервісу, а не рядок коду. Різниця принципова: у класичному багу є місце, куди розробник поставить фікс, а тут виправляти доводиться стан середовища — увімкнений дефолт, зайвий сервіс, забутий акаунт, надто балакучу сторінку помилки. Тому вона переживає код-рев'ю, й зелений : жоден із цих контролів на конфігурацію не дивиться. Для QA це і хороша, і погана новина водночас — знахідка дешева, бо видно її прямо у відповіді сервера чи в описі стенду, але саме такі пункти найчастіше не потрапляють у релізний чекліст під приводом «це ж не наш код». Практичний наслідок: тікет піде не в бекенд-команду, а до тих, хто володіє інфраструктурою, і формулювати його треба через стан («на стенді A порт 5432 відповідає ззовні»), а не через код.
Чому «у нас на стенді налаштовано інакше» — це знахідка, а не пояснення?
Бо канон вимагає протилежного: dev, QA і prod мають бути налаштовані однаково й різнитися лише обліковими даними. Поруч стоять ще дві вимоги, які роблять першу здійсненною: відтворюваний процес , щоб нове закрите середовище піднімалося швидко, і автоматизована перевірка конфігурацій в усіх середовищах — а якщо автоматизації немає, то принаймні ручна ревізія щороку. Для QA це переводить звичну фразу з розряду виправдань у розряд дефектів: розбіжність стенду й прода означає, що ви тестуєте не ту систему, яка поїде до користувача, і що частина конфігураційних дефектів прода на стенді фізично не відтвориться. Дзеркальний випадок так само названо дефектом поіменно — тестові фреймворки, залишені в проді.
Чому «ми нічого не міняли» — небезпечний стан, а не нейтральний?
Бо системи постачаються з узагальненими конфігураціями, які можуть не пасувати до завдання, що вони виконуватимуть на конкретному сайті. Дефолт не є поганим налаштуванням — він є налаштуванням, складеним без знання про ваш випадок. Тому в ревʼю платформи дивляться на стани: чи ввімкнено лише потрібні застосунку серверні модулі (вимкнений модуль зменшує й заразом знімає вплив вразливостей, які можуть зʼявитися в ПЗ вендора пізніше, якщо вони є лише у вже вимкнених модулях), чи стоять власні сторінки помилок замість дефолтних, чи працює серверне ПЗ з мінімізованими привілеями. Класичний приклад дефолту, видимого лише в доці платформи: machine.config і кореневий web.config .NET Framework типово читає будь-який користувач, тож адміністраторським секретам там не місце. Друга половина теми — : приклади застосунків, документацію й тестові сторінки прибирають перед розгортанням, щоб уникнути післяінсталяційної експлуатації, і це підперто чотирма реальними , у кожній з яких вразливість принесла демо-складова, а не код застосунку. Туди ж — вимога, що в проді не лишилося дебаг-коду чи розширень, і перегляд коментарів у HTML, куди інколи потрапляє й сам вихідний код. Сканер відомих файлів прискорює пошук, але певність дає лише повний перегляд умісту сервера з рішенням щодо кожного файлу.
Як шукають адмінінтерфейс і чому «на неї немає посилання» не є захистом?
Ціль тесту сформульовано як пошук саме прихованих і функціональності, тож відсутність посилання перевірку не скасовує. Каналів кілька й жоден не потребує експлойта: спроба вгадати шлях буває такою простою, як запит /admin чи /administrator, а подекуди адреса розкривається за секунди пошуковими запитами (Google dorks); перебір умісту сервера словником; посилання на адміністративну функціональність у всьому надісланому клієнту коді; конфігураційна чи довідкова документація продукту, якщо його розгорнуто в дефолтній конфігурації; власні дефолтні адмін-сторінки конкретного фреймворка; і навіть інший порт — адміністративний інтерфейс Apache Tomcat часто буває на 8080. Окремий вектор — підміна параметра: приховане поле admin=no чи кукі useradmin=0 не мають вмикати привілейовану функцію. Тест має і побічну шкоду, про яку джерело попереджає прямо: перебір по знайденій адмінці може заблокувати адміністративний обліковий запис. Закривають інтерфейс позитивною вимогою — харденінг, щоб адміністративні сторінки не були доступні всім (IP-фільтрація чи інші контролі), плюс перевірка, що жоден компонент не використовує чи конфігурацій: черга, кеш, база й брокер мають кожен свій постачальний акаунт, а публічні переліки дефолтних паролів однаково доступні й вам, і .
Що сервер віддає без запиту — і чому login.asp.old небезпечніший за чинний файл?
Три речі з одного ряду. Перша — , найочевидніший спосіб, у який помилково налаштований сервер розкриває несилані сторінки: каталоги запитують по одному й дивляться, які віддають перелік. Звʼязка з наступною темою неочевидна й важлива: бекап зазвичай не потрапляє в індекс пошуковика, бо на нього ніхто не посилається, — але з увімкненим переглядом каталогу пошуковик дізнається про нього сам. Друга — : старі копії віддаються як текст, а не виконуються, через своє розширення, тому login.asp.old дозволяє качати вихідний код login.asp; беруться такі копії з передбачуваних місць (редактори лишають file~, руки — .old, файлова система — снапшоти), а правку файлів по місцю на бойовій ФС джерело окремо називає особливо поганою звичкою. З них дістають облікові дані до бази в include-файлах, несилану адмінсторінку й стару версію з вразливістю, полагодженою у свіжішій, — тобто «баг полагоджено» і «вразливість недосяжна» це різні стани. Третя — : сервер за ним визначає, які технології задіяти, тож воно розкриває стек; .asa, .inc і .config не мають віддаватися ніколи (пряме звернення до connection.inc віддає його вміст), а архіви, .java, .txt, .bak, .old перевіряють на «чи це не залишок». Перевірка робиться покаталожно, а саме лише розширення оманливе й остаточним доказом не є.
Що перевіряють у правах на файли, і чому теза «бакет відкритий за замовчуванням» хибна?
— це дефект «ширше, ніж потрібно»: коли ресурсу задано налаштування прав, що дає доступ ширшому діапазону , ніж потрібно, наслідком є розкриття чутливої інформації або зміна ресурсу ненавмисними сторонами. Найпоказовіший випадок знову дефолтний: значення токена до API лежить у конфігураційному файлі, права на який після встановлення виставлені на читання для всіх. Перевіряють від імені непривілейованого акаунта — саме такий привілей матиме віддалений атакувальник, який уже скомпрометував сервіс іншою вразливістю, — і перевіряють конфіги, ключі й паролі, лог-файли, виконувані файли, тимчасові файли й каталог завантажень; інструмент тривіальний (ls, за потреби namei), класифікатор — -732. Лог у цьому переліку стоїть як обʼєкт контролю доступу, тож «до логів має доступ уся команда» — знахідка. Щодо хмари теза про дефолтну відкритість просто неправдива: за замовчуванням усі S3 приватні й доступні лише тим, кому доступ надано явно, а публічний доступ видається вручну — і на бакет, і на окремий обʼєкт, тож «бакет закритий» не є вердиктом про всі файли в ньому. Перевірка виглядає як звичайний негативний тест API: визначити URL сервісу, спробувати прочитати неавторизовані дані й залити довільний файл звичайним curl; правильно закритий бакет відповідає AccessDenied на операції PutObject.
Які перевірки периметра не стосуються коду взагалі — піддомен, методи, файл політики?
— вразливість, успішна експлуатація якої дозволяє супротивнику заявити права на піддомен жертви й перебрати контроль над ним; потрібні дві умови разом: запис указує на неіснуючий або неактивний ресурс, і провайдер, який його хостить, неналежно перевіряє володіння піддоменом. Уразливий не лише CNAME, а й A, MX, NS, TXT, і найважчий випадок саме NS — він може віддати повний контроль над усією DNS-зоною й доменом. Перевірка є інвентаризацією: перелічити всі домени, зокрема колишні, і виявити забуті чи неправильно налаштовані; чужий «404 — File not found» на нашому піддомені названо чіткою вказівкою на вразливість, а лікування — прибрати запис із зони. Методи HTTP потрапляють у той самий чекліст, бо деякі менш відомі дієслова можна вжити для лихих цілей, якщо вебсервер налаштовано хибно: увімкнений PUT дозволяє покласти в систему довільний і потенційно шкідливий вміст аж до віддаленого виконання коду, вигадані методи на кшталт BILBAO показують фільтр, побудований на переліку відомих дієслів, а заголовки X-HTTP-Method, X-HTTP-Method-Override і X-Method-Override перевіряють, чи заборона методу на периметрі справді є забороною; TRACE подають як гігієну конфігурації, бо сучасні браузери дозволяють лише за інтеграції з технологіями на кшталт Flash. Файл крос-доменної політики описує дозволи, з якими вебклієнт може звертатися до даних на іншому домені: головний файл лежить у корені й перевіряється першим, тож crossdomain.xml і clientaccesspolicy.xml просять із кореня застосунку й із кожної знайденої теки; погана конфігурація уможливлює CSRF і доступ третіх сторін до чутливих даних, а політики із зірочкою розглядають особливо уважно.
Чому докладне повідомлення про помилку вважають вразливістю, а не косметикою?
Тому що атака рідко стартує з експлойта — вона стартує з розвідки, і саме на цій фазі збирають назви та версії сервера застосунку, фреймворків і бібліотек. Необроблений виняток, відрендерений користувачеві, віддає ці дані безоплатно: у прикладах джерела це версії Struts2 і Tomcat у тілі сторінки та службовий рядок про те, що повний кореневої причини лежить у логах Apache Tomcat/7.0.56. Найгірший різновид — повідомлення про помилку SQL-запиту, у якому світиться ще й шлях установлення сайту: за таким визначають точку , тобто повідомлення не просто описує систему, а вказує, куди бити далі. Тому дефект обробки помилок оцінюють не за тим, «чи гарно виглядає сторінка», а за тим, скільки корисного для наступного кроку атаки вона віддала.
Що таке A10 Mishandling of Exceptional Conditions і за яким критерієм визначають, що умову оброблено неправильно?
Це нова категорія редакції 2025 року, куди винесли ; вона обʼєднує 24 CWE, а провідними названо дві: CWE-636 (небезпечне падіння у відкритий стан) і CWE-209 — повідомлення з чутливою інформацією всередині. Наслідки описані через усі три властивості: конфіденційність, доступність і цілісність. Критерій зручний тим, що перевіряється без словників: якщо застосунок опинився в стані, де він не впевнений щодо своєї наступної інструкції, — умову оброблено неправильно. Сценарії теж упізнавані: системна помилка бази, показана користувачеві, після якої атакувальник навмисно провокує нові помилки, щоб зібрати системну інформацію й точніше націлити ; і вичерпання ресурсів, коли застосунок ловить виняток під час завантаження файлу, але захоплені ресурси не звільняє.
Коли сервер має відповідати 4xx, а коли 5xx, і навіщо взагалі моніторити 5xx?
4xx — реакція на запит, що впав через помилку на боці HTTP-клієнта; 5xx — на непередбачений баг сервера. Вимога сформульована жорсткіше, ніж «повертайте правильний код»: перекрити треба всі можливі режими , а 5xx уживати лише там, де застосунок справді не може виконати запит, і при цьому не класти у відповідь вміст, який розкриває деталі реалізації. Моніторинг серверних кодів має окрему цінність, і не тільки для SRE: сплеск 5xx добре показує, на яких наборах даних застосунок валиться, тобто фактично підказує тестувальнику, де шукати .
Кандидат каже: «В OWASP написано — стек-трейс користувачеві показувати не можна». Де тут неточність?
Формулювання правильне по суті, але хибне як цитата, і на співбесіді це помітно. Шпаргалка Error Handling окремої вимоги саме про стек- не містить — вона забороняє віддавати у відповіді вміст, який розкриває деталі реалізації, а стек-трейс є лише одним із таких вмістів. Поіменно стек-трейс користувачеві названо ознакою категорії A02, а як окрема іменована слабкість він живе в CWE-209 усередині A10. Практична різниця не в педантизмі: якщо шукати рівно рядок «стек-трейс», повз проходять шляхи файлів, назви внутрішніх хостів, фрагменти SQL і назви бібліотек — усе те, що технічно стек-трейсом не є, а розвідданими є цілком.
Як переконатися, що застосунок не розкриває зайвого в повідомленні про помилку?
Процедура складається з чотирьох кроків. Спершу помилку провокують навмисно: відʼємна кількість у замовленні, поле не того типу, неіснуючий ідентифікатор, завеликий файл, обірваний JSON. Далі дивляться не на формулювання тексту, а на склад відповіді — чи немає в тілі маркерів реалізації: фрагментів стеку, шляхів на диску, назв і версій компонентів, коду помилки СУБД. Третій крок найчастіше пропускають: перевірити другий бік пари, тобто чи зʼявився в серверному лозі запис про цю саму подію — узагальнена відповідь без запису в лозі означає не безпеку, а сліпоту. Четвертий — закріпити перевірку автотестом, бо це типова : детальні помилки повертаються разом із дебагом, увімкненим «на пів години» під час розслідування інциденту.
Чому лог називають водночас засобом захисту й ціллю атаки?
Тому що корисність логу для розслідування робить його цінним і для атакувальника. Механізми логування й зібрані події захищають одразу з кількох боків: щоб їх не підмінили дорогою, щоб до них не дістався чужий, щоб уже збережене не змінили й не витерли — і причина саме в тому, що в журналі осідають персональні та інші чутливі дані, а поруч сліди коду й логіки застосунку. Атакують лог у трьох напрямах: конфіденційність (прочитані персональні дані дають матеріал для атак уже на самих користувачів, а технічні секрети — для наступного кроку вглиб системи), доступність (лог-файли заливають, щоб вичерпати місце на диску й позбавити систему подальшого логування) і підзвітність (у журнал заганяють хибну ідентичність, щоб приховати справжнього виконавця). Два останні напрями підступні тим, що застосунок працює як ні в чому не бувало: з ладу виведено спостережність, а не сам сервіс. Звідси й перевірні вимоги: логи не мають лежати у вебдоступних місцях (а якщо вже лежать — з обмеженим доступом і MIME-типом plain text, не HTML), право читати їх обмежують і періодично переглядають, а відмова самої підсистеми логування не повинна ні заважати роботі застосунку, ні відкривати витік.
Що таке інʼєкція в лог (log injection) і як її перевірити за кілька хвилин?
Це запис у журнал даних, які підробляють його структуру: атакувальник вкладає у власне поле символи повернення каретки (CR), переводу рядка (LF) або розділювачі формату — і в лозі зʼявляється зайвий рядок, який виглядає як окрема справжня подія. Запобігає цьому санітизація даних події перед записом, тож перевірка зводиться до спроби обійти саме її. Беруть поле, яке точно логується — логін, User-Agent, назву файлу, — вкладають туди CR/LF разом із розділювачем формату й дивляться, чи розпався запис на два. Якщо в журналі зʼявився підроблений другий рядок, під питанням опиняється не лише лог, а й усе, що на ньому будується: алерти, кореляція подій, розслідування інциденту. Поруч перевіряють і другий бік — чи не можна саме логуванням вичерпати ресурси: заповнити диск або перебрати місце під журнал бази.
Чого не можна писати в лог, і чим «нечутливі» дані відрізняються від чутливих?
Список першого класу конкретний, тож на співбесіді його й чекають: код застосунку, значення ідентифікації сесії, токени доступу, паролі автентифікації, рядки підключення до бази, ключі шифрування та інші первинні секрети, реквізити банківського рахунку й дані власника платіжної картки, а також чутливі персональні дані та окремі форми PII — здоровʼя, державні ідентифікатори, вразливі особи. Ці значення або не пишуть узагалі, або прибирають, маскують, санітизують, хешують чи шифрують; якщо сесію треба відстежити, у лог кладуть її хеш, а не сам ідентифікатор. Другий клас — те, що для розслідування потрібне, але вимагає окремого поводження ще до того, як ляже в журнал: внутрішні мережеві імена та адреси, шляхи файлів, а також нечутливі персональні дані на кшталт імен, телефонів і поштових адрес. Тож відмовка «це ж просто імʼя» запису без обробки не виправдовує. Окремо варто не плутати цю тему з маскуванням секретів у CI: у пайплайні питання в тому, чи не спливе секрет у виводі , а тут — чи таке значення взагалі дозволено писати в журнал застосунку.
Що таке знеособлення (de-identification) і чому запис даних сам по собі буває проблемою?
— це підготовка персональних даних до запису, коли особу для розбору знати не потрібно або надто високий: прямі й непрямі ідентифікатори видаляють, перемішують (scrambling) або замінюють псевдонімами. Критерій вибору не «як зручніше команді», а чи потрібна ідентичність для мети запису — і той самий критерій, до речі, працює в . Друга половина відповіді та, яку в QA згадують рідко: сам запис уже є обробкою даних. Логувати не можна те, на що немає правової підстави: прослуховування частини комунікацій, контроль за працівниками чи збирання окремих категорій даних без згоди подекуди прямо суперечать закону. Не записують і того, на що людина сказала «ні», і того, чия згода вже втратила силу. Є ще вимога, яку рідко вносять до тест-плану: коли організація не здатна поручитися, що чутлива інформація (логи в тому числі) не спливе й не буде вжита не за призначенням, вона зобовʼязана сказати про це людям ясною мовою — щоб вибір був поінформованим.
Як застосунок зливає IP-адресу користувача, не маючи жодного дефекту в коді?
Через сторонній контент, який рендериться у стрічці жертви. Досить того, щоб продукт дозволяв вставити картинку з чужого домену — в аватарі, у підписі, у вкладеному фото. Атакувальник кладе таку картинку на власний сервер і читає журнал HTTP-запитів за нею: браузер жертви приходить по неї сам і приносить свою справжню IP-адресу. Механіка ідентична витоку через HTML-листи, і саме через неї більшість поштових клієнтів за замовчуванням не вантажить зовнішній контент. Практичний висновок для тест-дизайну: будь-яка можливість вставити зовнішній ресурс у контент, видимий іншим користувачам, є перевіркою приватності, а не тільки продуктивності чи верстки.
«У нас усе в контейнері» — це аргумент безпеки?
Сам по собі — ні, це нейтральний факт. За правильного використання контейнеризація здатна підвищити безпеку порівняно з запуском застосунків прямо на хості, але певні хибні конфігурації рівень безпеки навпаки знижують і додають нових вразливостей. Корисно одразу прибрати «контейнер — маленька віртуалка»: ядро в й хоста спільне, тож уразливе ядро хоста означає вразливі контейнери. Далі йдуть стани з коробки, які треба міняти явно: контейнер за замовчуванням працює від root (непривілейований користувач названо найкращим способом закрити ), --privileged роздає всі можливості ядра Linux (безпечніше скинути їх усі через --cap-drop all і повернути потрібні), --security-opt=no-new-privileges перекриває здобуття привілеїв через setuid/setgid-бінарники, звʼязність між контейнерами (icc) увімкнена, дефолтний профіль seccomp / AppArmor / SELinux беруть за базову лінію, а не вимикають, файлову систему переводять у --read-only з --tmpfs під тимчасові файли, найкращим способом не отримати відмову в обслуговуванні названо ліміти — на CPU, памʼять, дескриптори, процеси й перезапуски, а демон без потреби не запускають на рівні логування debug. Усе перелічене є станами, а не сценаріями, тож перевіряється середовища, а не тестом; окремо варто спитати про режим rootless, у якому навіть утеча з контейнера не дає атакувальнику root на хості.
У фаєрволі стоїть заборона, а сервіс із контейнера відповідає ззовні. Як таке можливо?
Це наслідок порядку правил, а не помилки адміністратора в самому фаєрволі. Docker не просить фаєрвол про послугу: правила iptables і nftables він пише сам, повз UFW. Публікація порту додає записи, які роблять його видимим на кожному інтерфейсі й з будь-якої адреси-джерела, а стоять ці записи в ланцюжку попереду явних DENY — тож до заборони справа просто не доходить. Тому поширена впевненість, що фаєрвол хоста прикриває весь вхідний трафік разом із контейнерним, на практиці не тримається. Для теми глави це найпряміша ілюстрація: службовий виявився доступним ззовні без жодного дефекту в коді. Практичний висновок для перевірки: доказом є спроба зʼєднання з зовнішньої машини, а не рядок у конфігурації фаєрвола — читання конфігів тут дає хибне «зелено».
Чому доступ до сокета демона прирівнюють до root на хості, і чи рятує монтування «лише для читання»?
/var/run/docker.sock — первинна точка входу в Docker API, і власником його є root. Хто дістався сокета, той дістався всього API демона, тож джерело формулює наслідок без помʼякшень: видача доступу до сокета дорівнює наданню необмеженого root-доступу до хоста. Саме тому правило звучить максимально жорстко: сокет не виставляють нікому, включно з іншими контейнерами — популярний патерн «змонтуємо сокет у контейнер CI, щоб він міг збирати образи» це рівно той випадок. «лише для читання» проблему не знімає: планку складності для атакувальника він піднімає, а сам доступ лишає на місці. У ревізії стенду це перевіряється однією командою — переліком монтувань контейнера, і знайдений сокет варто заводити як окрему знахідку, а не примітку.
Три кейси, у яких вердикт знімається зі стану середовища, а не з коду: розбір реальної відповіді про помилку (де тут витік, а де просто негарно), Playwright-перевірки складу тіла й підробки рядка в лозі та ревізія стенду двома зрізами — дефолти за таблицею «дефолт → чим перевірити → що вважати знахідкою» і прохід за чеклистом конфігурації . Скрізь — що дивитися і чому.
Кейс 1. Відповідь про помилку: розвідка на блюдці
Тестуємо оформлення замовлення, надсилаємо qty зі значенням -1 і замість очікуваної валідації отримуємо ось це:
HTTP/1.1 500 Internal Server Error
Content-Type: text/html; charset=utf-8
Server: Apache-Coyote/1.1
X-Powered-By: Servlet 3.0
<h1>HTTP Status 500 - Internal Server Error</h1>
<p><b>type</b> Exception report</p>
<p><b>root cause</b> java.sql.SQLException: ORA-00933: SQL command not properly ended
at com.shop.order.OrderDao.insert(OrderDao.java:214)
at com.shop.order.OrderService.create(OrderService.java:88)</p>
<p>Config path: /opt/app/shop/WEB-INF/classes/db.properties</p>
<p><b>note</b> The full stack trace of the root cause is available in the
Apache Tomcat/7.0.56 logs.</p>
Тікет тут не один, і сортувати їх варто за тим, що саме віддано :
| Що видно у відповіді | Що це дає атакувальнику | Куди це віднести |
|---|---|---|
java.sql.SQLException з кодом ORA-00933 | Тип СУБД і те, що параметр доїжджає до запиту в сирому вигляді | Найважча знахідка: помилка запиту разом зі шляхом підказує точку інʼєкції |
at com.shop.order.OrderDao... | Структуру пакетів, імена класів і рядок коду | Стек-трейс користувачеві — ознака A02, іменована слабкість CWE-209 |
Apache Tomcat/7.0.56, Apache-Coyote/1.1, Servlet 3.0 | Точну версію контейнера сервлетів для добору відомих експлойтів | Розвідка: версія стека в тілі й у заголовках |
/opt/app/shop/WEB-INF/classes/db.properties | Шлях установлення й місце файлу з налаштуваннями підключення | Розкриття деталей реалізації |
Сам код 500 на відʼємній кількості | Валідація не спрацювала, до бази поїхало те, що мало впасти на вході | Окремий дефект: очікується 4xx, а не падіння |
Три речі, які тут легко пропустити:
- Перевіряти треба не текст, а склад. Формулювання відрізняються від фреймворка до фреймворка, а маркери повторюються:
at com.,Traceback,ORA-,SQLSTATE,/opt/,/var/www/, назва й версія сервера. на конкретну фразу протухне після першого ж оновлення бібліотеки, асерт на клас маркерів — ні. - Друга половина пари не видно з відповіді. Правильна поведінка — узагальнено користувачеві, деталі в серверний лог, тож після виправлення варто переконатися, що подія в лозі зʼявилась. Порожня відповідь без запису в журналі це не безпека, а сліпота: інцидент буде нічим розслідувати.
ServerіX-Powered-By— гігієна, а не головна знахідка. Прибрати їх варто, але в одному тікеті з розкритим SQL-винятком вони розмиють пріоритет. Заводьте окремо.
Кейс 2. Playwright: склад тіла помилки й проба на інʼєкцію в лог
Обидві перевірки дешеві й добре живуть у — саме тому, що дефект повертається сам: детальні помилки вмикають «на пів години» під час розслідування інциденту й забувають вимкнути.
import { test, expect } from '@playwright/test';
// маркери реалізації, які не мають доїжджати до клієнта
const LEAK_MARKERS = [
'at com.', 'at org.', 'Traceback (most recent call last)',
'SQLSTATE', 'ORA-', 'ER_', 'node_modules/',
'/var/www/', '/opt/app/', 'WEB-INF',
];
const BAD_PAYLOADS = [
{ name: 'відʼємна кількість', data: { qty: -1, sku: 'A-1' } },
{ name: 'не той тип', data: { qty: 'ten', sku: 'A-1' } },
{ name: 'відсутнє поле', data: { sku: 'A-1' } },
];
for (const payload of BAD_PAYLOADS) {
test(`помилка не розкриває деталей реалізації: ${payload.name}`, async ({ request }) => {
const res = await request.post('/api/orders', { data: payload.data });
// сміттєвий ввід має відхилятися свідомо: не проїжджати і не валити сервер
expect(res.status(), 'очікуємо явну відмову, а не 2xx').toBeGreaterThanOrEqual(400);
expect(res.status(), 'очікуємо 4xx, а не падіння сервера').toBeLessThan(500);
const body = await res.text();
for (const marker of LEAK_MARKERS) {
expect(body, `у тілі відповіді знайдено маркер «${marker}»`).not.toContain(marker);
}
});
}
Проба на робиться тим самим інструментом: кладемо CR/LF і розділювач формату в поле, яке точно потрапляє в журнал, і дивимося, чи розпався запис на два рядки.
import fs from 'node:fs/promises';
test('дані події санітизуються перед записом у лог', async ({ request }) => {
const marker = `probe-${Date.now()}`;
// підроблений «другий рядок» усередині одного значення
const injected = `${marker}\r\n2026-08-03 12:00:00 | INFO | user=admin | action=login-success`;
await request.get('/api/profile', { headers: { 'User-Agent': injected } });
const log = await fs.readFile('/srv/stand/logs/app.log', 'utf8');
const forged = log
.split('\n')
.filter((line) => line.includes('action=login-success') && !line.includes(marker));
expect(forged, 'у лозі зʼявився підроблений рядок події').toHaveLength(0);
});
Що дивитися і чому:
- Пара асертів на статус тут не про коди, а про контрольовану . Нижня межа не дає сміттєвому вводу тихо проїхати з
2xx, верхня ловить падіння: сервер, який валиться на кривому вводі, вже перебуває в стані «не впевнений щодо наступної інструкції» — це і є неправильно оброблена нештатна умова, незалежно від того, що потрапило в тіло. - Читання файлу лога працює лише на стенді, яким ви володієте. Якщо доступу до файлової системи немає, ту саму пробу роблять через пошук у системі збору логів за унікальним маркером — важлива не техніка читання, а факт появи зайвого рядка.
- Проба з
User-Agentперевіряє не лише лог. Розпад рядка ламає все, що будується згори: кореляцію подій, алерти, розслідування інциденту. Тому знахідку заводять не як «косметика в журналі», а як дефект підзвітності. - Асерт на порожню відповідь без перевірки лога — половина роботи. Другу половину пари перевіряють окремим кроком: подія про помилку має бути в журналі, інакше застосунок став тихим, а не безпечним.
Кейс 3. Ревізія стенду: два зрізи, які не перевіряються тестом
Дефолти середовища є станами, тож дивляться на них , а не сценарієм. Зрізів два, і обидва лягають у таблицю, яку можна пройти перед релізом: дефолти рантайму контейнера й чекліст конфігурації та розгортання WSTG з одинадцяти тестів.
Зріз перший — стани з коробки:
| Стан із коробки | Чим перевірити | Що вважати знахідкою |
|---|---|---|
| Користувач контейнера | docker exec <name> id | uid=0(root) — потрібен непривілейований користувач |
| Можливості ядра | docker inspect --format '{{.HostConfig.Privileged}}' <name> | true — замість цього --cap-drop all плюс потрібні поіменно |
| Здобуття привілеїв усередині | пошук no-new-privileges у SecurityOpt | опції немає — setuid-бінарник підніме привілеї |
| Звʼязність між контейнерами | налаштування icc демона, мережа docker0 | увімкнено за замовчуванням: усі контейнери бачать одне одного |
| Профіль безпеки | SecurityOpt контейнера | seccomp=unconfined — дефолтний профіль мав лишитися базовою лінією |
| Файлова система | docker inspect --format '{{.HostConfig.ReadonlyRootfs}}' <name> | false без причини — очікується --read-only плюс --tmpfs |
| Ліміти ресурсів | Memory, NanoCpus, PidsLimit, політика перезапуску | нулі скрізь: відмова в обслуговуванні зупиняє й сусідів по хосту |
| Рівень логування демона | конфігурація демона | запуск на рівні debug без потреби |
| Сокет демона | docker inspect --format '{{json .Mounts}}' <name> | будь-яка згадка /var/run/docker.sock, зокрема ro |
| Опубліковані порти | спроба зʼєднання з ЧУЖОЇ машини | відповідає порт, якого не мало бути видно ззовні |
Два останні рядки заслуговують на окремий коментар — саме на них найчастіше помиляються.
Сокет демона. Аргумент «ми змонтували його лише для читання, збірка образів у CI цього потребує» звучить розсудливо, але доступ до /var/run/docker.sock дорівнює необмеженому root-доступу до хоста: сокет є первинною точкою входу в Docker API, а власник його — root. ro ускладнює експлуатацію, а не прибирає її, тож пункт лишається знахідкою.
Порт. Тут єдина перевірка, яку не можна робити читанням конфігурації:
# з ІНШОЇ машини, а не з хоста, де крутиться сервіс
nc -zv stand.example.com 5432
curl -sS -o /dev/null -w '%{http_code}\n' http://stand.example.com:9090/metrics
Причина в порядку правил, а не в помилці адміністратора: Docker керує власними правилами iptables і nftables, обходячи UFW, а публікація порту робить його видимим на кожному інтерфейсі й з будь-якої адреси, і ці записи стоять попереду явних DENY. Тому «у фаєрволі стоїть заборона» доказом не є — доказом є мовчання порту у відповідь на спробу зʼєднання ззовні. Це найкоротша ілюстрація теми глави: службовий відкрито назовні, а помилки в коді немає жодної.
Зріз другий — той самий стенд за чеклистом конфігурації й розгортання: одинадцять тестів із власною нумерацією, кожен зі своїм . Приблизно половина з них перевіряється відповіддю сервера, решта — інспекцією середовища; це два різні прогони з різними правами доступу.
| Пункт | Чим перевірити | Що вважати знахідкою |
|---|---|---|
| 4.2.1 інфраструктура | звірка відкритих портів із переліком під контролем змін | порт, якого в переліку немає; переліку немає взагалі |
| 4.2.2 платформа | увімкнені серверні модулі, сторінка помилки, привілеї процесу | дефолтна сторінка вебсервера; модуль, який застосунку не потрібен |
| 4.2.2 залишки | запит демо-сторінок і документації інсталяції; перегляд HTML | доступний приклад застосунку; коментар із внутрішніми даними чи закоментованим кодом |
| 4.2.3 розширення | ті самі шляхи з іншим розширенням, покаталожно | .inc, .config, .asa віддаються як текст; .bak чи .old, які ніхто не планував публікувати |
| 4.2.4 копії й лістинг | запит каталогів; login.<ext>.old, .bak, file~, архів | каталог віддає перелік; стара копія качається як вихідний код |
| 4.2.5 адмінка | /admin, /administrator, словник, посилання у клієнтському коді, порт 8080 | інтерфейс відповідає без IP-фільтрації; підходять дефолтні креденшели |
| 4.2.6 методи | запити різними дієсловами, зокрема вигаданими; заголовки підміни методу | PUT приймається; X-HTTP-Method-Override міняє код відповіді |
| 4.2.7 HSTS | пункт того самого чекліста, але його канон — глава 8 | критерії й процедура — там |
| 4.2.8 крос-доменна політика | GET /crossdomain.xml, GET /clientaccesspolicy.xml, те саме по теках | файл є, а в ньому зірочка замість переліку доменів |
| 4.2.9 права | ls і namei по конфігах, ключах, логах, каталогу завантажень | конфіг із токеном читається всіма; логи відкриті будь-кому на хості |
| 4.2.10 піддомен | перелік записів зони, зокрема колишніх; звернення до кожного | чужий 404 — File not found на нашому піддомені; запис без живого ресурсу за ним |
| 4.2.11 сховище | curl на читання й на заливання довільного файлу | заливання проходить замість AccessDenied на PutObject |
Три речі, які легко пропустити в цій ревізії:
- Пункт без еталона не перевіряється. «Зайвий порт» існує лише тоді, коли є перелік потрібних портів під контролем змін; те саме з модулями сервера. Спершу артефакт очікуваного, потім звірка — інакше вердикт зводиться до смаку ревізора.
- Зелений сканер закриває не той самий обсяг. Автоматика судить за версією сервера й помиляється в обидва боки, а бачить лише виставлені назовні елементи: бекенд автентифікації, база й реверс- лишаються неперевіреними, доки їх не перевірили окремо.
- Знахідка адресується інфраструктурі, а не автору сторінки. Формулювання тікета — через стан («на стенді A каталог
/uploads/віддає перелік файлів»), а не через код; так само й пріоритет: розкритий вихідний код зі старої копії важить більше, ніж відсутній заголовок.
Хибна конфігурація як клас
- Пояснюю клас без коду: створює стан середовища — непройдений (hardening), криві хмарні дозволи, зайві порти/служби/сторінки/акаунти/привілеї/тестові фреймворки, дефолтні акаунти з незміненими паролями, надто інформативні помилки, відсутні чи небезпечні . У :2025 це A02 (підйом із пʼятого місця), і ознаки категорії знайшлися в усіх протестованих застосунках.
- Тримаю три вимоги запобігання: відтворюваний процес харденінгу, однакова конфігурація dev/QA/prod із різними обліковими даними, автоматизована ревізія конфігурацій (без автоматизації — щонайменше ручна щороку). Тому «на стенді в нас інакше» — знахідка, а тестові фреймворки в проді — названий поіменно дефект.
Чекліст конфігурації середовища (WSTG 4.2)
- Знаю, що конфігурація й розгортання — окрема група тестів із власною нумерацією і одинадцятьма пунктами: мережева інфраструктура, платформа застосунку, обробка розширень файлів, старі копії й , адмінінтерфейси, методи HTTP, , файл крос-доменної політики, , , хмарне сховище.
- Памʼятаю, що чекліст каже, що перевіряти, а не яким має бути значення: правильне звіряють із базовими лініями чи бенчмарками конфігурації (CIS-CAT Lite, Microsoft Attack Surface Analyzer, NIST National Checklist Program), а рекомендована конфігурація залежить від політики сайту й функцій серверного ПЗ. Вимагаю перелік потрібних застосунку портів під контролем змін: без нього критерію «зайвий порт» не існує.
- Не приймаю «сканер зелений» за звіт про конфігурацію: судження за версією сервера помиляється в обидва боки, а бекенди автентифікації, база й реверс- в поле зору не потрапляють. Радіус ураження памʼятаю теж: однієї вразливості досить, щоб підірвати всю інфраструктуру, а дрібниця переростає в для сусіда по серверу.
- Перевіряю платформу як стани й залишки: увімкнено лише потрібні застосунку модулі, стоять власні сторінки помилок, серверне ПЗ працює з мінімізованими привілеями,
machine.configі кореневийweb.config.NET Framework не тримають секретів (їх типово читає будь-хто), приклади застосунків, документацію й тестові сторінки прибрано перед розгортанням, у проді немає дебаг-коду, а в HTML — коментарів із внутрішніми даними.
Адмінка, права, периметр і хмара
- Шукаю адмінінтерфейс, а не логінюся в нього:
/adminі/administrator, перебір словником, посилання у клієнтському коді, дефолтні шляхи фреймворка, дока продукту, інший порт (Tomcat часто на 8080), підміна параметра — приховане полеadmin=noчи кукі; перебір планую з оглядкою на блокування адміністративного облікового запису. - Захід формулюю позитивно: харденінг з IP-фільтрацією чи іншими контролями плюс перевірка, що жоден компонент — черга, кеш, база, брокер — не лишився на чи конфігурації; переліки дефолтних паролів публічні.
- Дивлюся, що сервер віддає сам: лістинг каталогів покаталожно (каталог із увімкненим переглядом сам віддає пошуковику бекап, на який ніхто не посилається), передбачувані копії
login.<ext>.old,.bak,file~, архіви — і два класи розширень:.asa,.inc,.configне віддаються ніколи, а архіви,.java,.txt,.bak,.oldперевіряю на «чи це не залишок». Стара копія качається як текст, тож «баг полагоджено» і «вразливість недосяжна» — різні стани. - Права на файли читаю від імені непривілейованого акаунта, бо саме такий привілей матиме після компрометації сервісу: конфіги, ключі й паролі, лог-файли, виконувані й тимчасові файли, каталог завантажень (
ls, за потребиnamei, -732). Дефект не в тому, що секрет лежить у конфізі, а в тому, хто цей конфіг читає: типові права після встановлення — «читання для всіх». - Периметр перевіряю поза кодом: піддомени — інвентаризацією записів, зокрема колишніх (
A,CNAME,MX,NS,TXT), де чужий404 — File not foundє знахідкою, аNSможе віддати всю DNS-зону; методи — запитами різними й вигаданими дієсловами та заголовкамиX-HTTP-Method-Overrideі подібними (увімкненийPUTкладе в систему довільний вміст,TRACE— гігієна конфігурації);crossdomain.xmlіclientaccesspolicy.xmlпрошу з кореня й із кожної теки, а зірочку в політиці розглядаю окремо. - Не повторюю тезу про «відкритий за замовчуванням бакет»: S3 приватні, а публічний доступ видається вручну — і на бакет, і на окремий обʼєкт. Перевіряю обидві дії звичайним
curl, читання і заливання; очікуваний результат закритого бакета —AccessDeniedнаPutObject.
Помилка як розвідка
- Пояснюю механізм замість «бо негарно»: починається з розвідки, і назви з версіями сервера, фреймворків та бібліотек у тілі помилки вже є її результатом; найгірший різновид — помилка SQL-запиту зі шляхом установлення, за якою визначають точку .
- Орієнтуюся в A10 Mishandling of Exceptional Conditions: нова категорія редакції 2025, 24 CWE, провідні CWE-209 і CWE-636, критерій — застосунок не впевнений щодо своєї наступної інструкції. Заходи назву поіменно: ловити системну помилку в місці виникнення плюс глобальний обробник, відкочувати обірвану цілком, ставити ліміти (rate limiting, квоти, ), тримати обробку в одному місці.
- Цільову поведінку тримаю як пару й перевіряю обидві половини: у відповіді немає маркерів реалізації (фрагменти стеку, шляхи, версії, коди СУБД), а в серверному лозі є запис про ту саму подію;
4xx— помилка на боці клієнта,5xx— непередбачений баг сервера, і5xxмоніторять, бо вони показують, на яких даних застосунок валиться. Закріплюю це автотестом, бо дефект повертається разом із тимчасово ввімкненим дебагом. І не плутаю формулювання: окремої вимоги про шпаргалка Error Handling не містить — заборонено вміст із деталями реалізації, а стек- у клієнта проходить як ознака A02 та іменована слабкість CWE-209 усередині A10.
Лог і персональні дані
- Знаю, чому корисність логу робить його ціллю, і назву три напрями атаки: конфіденційність (прочитане стає плацдармом), доступність (лог заливають до вичерпання диска), підзвітність (у журнал заганяють хибну ідентичність) — у двох останніх застосунок працює як ні в чому не бувало. Вимоги перевіряю запитом або переглядом прав: журнал не лежить у вебдоступному місці (а якщо лежить — обмежений доступ і MIME-тип plain text, не HTML), право читання обмежене й періодично переглядається, підсистеми логування не ламає застосунок і не відкриває витік.
- Можу за пʼять хвилин перевірити (log injection):
CR,LFі символ-розділювач у поле, що гарантовано їде в журнал (логін,User-Agent). І памʼятаю, що саме логування є вектором відмови в обслуговуванні — ним не має бути можливо заповнити диск чи перебрати місце під журнал транзакцій бази. - Відтворю обидва класи даних: перший (код застосунку, значення ідентифікації сесії, токени доступу, паролі, рядки підключення до бази, ключі шифрування, дані рахунку чи картки, чутливі персональні дані) не пишуть напряму, другий (внутрішні мережеві імена та адреси, шляхи файлів, імена, телефони, email) потребує окремого поводження ще до запису. Сам запис уже є обробкою: без правової підстави й після відмови користувача не логують, а коли ідентичність для мети не потрібна — знеособлюють (видалення, перемішування, прямих і непрямих ідентифікаторів). Витікають персональні дані не лише логом: картинка з чужого домену в аватарі чи вкладенні віддає IP жертви власнику того домену.
Дефолти середовища: контейнер, порт, сокет
- Перелічу дефолти , які змінюють явно: root усередині,
--privilegedз усіма можливостями ядра проти--cap-drop all,--security-opt=no-new-privileges, увімкненийiccчерез мостову мережуdocker0, дефолтний профіль seccomp/AppArmor/SELinux як базова лінія,--read-onlyплюс--tmpfs, ліміти ресурсів і перезапусків, демона неdebug. Це стани, а не сценарії: їх дивляться ревізією стенду, тестом не покриєш. Ядро в контейнера з хостом спільне, а режим rootless додає те, що навіть утеча з контейнера не дає root на хості. - Знаю дві найдорожчі помилки середовища:
/var/run/docker.sockдорівнює необмеженому root-доступу до хоста (монтування «лише для читання» лише ускладнює експлуатацію), а Docker пише власні правилаiptables/nftablesповз UFW — опублікований порт виставлено на кожному інтерфейсі попереду явнихDENY, тож закритість доводить мовчання порту у відповідь на спробу зʼєднання з чужої машини, а не рядок у конфігу. Звіт сканера читаю з уточненням класу (секрети, відомі вразливості, хибні конфігурації образу), а Docker Secrets тримаю в його межах — образи й команди запуску, не Kubernetes, де секрети за замовчуванням зберігаються відкритим текстом.
Квіз
Перед стартом
- Питань: 17
- Поріг «зараховано»: ≥70% правильних відповідей.
- Результат впливає на прогрес; завалені питання підуть у чергу повторення.
- Квіз впливає на компліт теми: тема стає «пройдено», лише коли прочитано теорію І квіз складено на ≥70%.
Питання
Чому хибна конфігурація переживає код-рев'ю й зелений пайплайн?