Інʼєкції: SQL, NoSQL, command
Зміст
Поле пошуку, параметр ?id=42, заголовок User-Agent — для застосунку це дані. Для інтерпретатора, якому вони приїдуть уже склеєними в готовий рядок команди, це може виявитися кодом. На цьому розриві тримається вся тема: розробник думає про ввід як про значення, а база, шел чи каталог розбирають отриманий рядок як текст команди — межі між «моїм синтаксисом» і «чужими даними» там ніхто не проводив.
Для QA це тема, де зелений функціональний тест не доводить нічого: форма працює, замовлення створюється, статус 200 — і той самий параметр дає читати чужу таблицю. Ця глава — канонічний виклад на сайті, інші глави посилаються сюди. Синтаксис SQL і механіка запитів — матеріал розділу про бази даних; тут інʼєкція як і пейлоад як техніка. Інʼєкція у вивід, який виконує браузер, — окрема глава «XSS: міжсайтовий скриптинг».
Механізм: код і дані в одному рядку
(injection flaw) означений через рух даних, а не через технологію: він виникає, коли застосунок надсилає недовірені дані інтерпретаторові. Мішені OWASP перелічує одразу — SQL-запити, LDAP-запити, XPath-запити, команди операційної системи, аргументи програм. Це один клас дефекту, форми якого різняться технологією-мішенню, а не механізмом.
Суть найточніше формулюють на прикладі SQL: команди вставляють у ввід, призначений для даних, щоб вплинути на виконання заздалегідь визначених команд. Метасимвол у полі даних переносить команду в площину керування (control plane), де її не було, — і працює це тому, що SQL реальної межі між нею та площиною даних (data plane) не проводить. Каталог слабкостей описує те саме з боку коду: продукт будує команду із зовні впливаного входу й не нейтралізує спецелементи, здатні змінити задуману команду (-89).
Одну межу варто провести одразу: інʼєкція коду (code injection) дозволяє додати власний код, який виконає застосунок, а в власного коду не треба — розширює наявну функцію, яка й так виконує системні команди.
Інʼєкція в мапі ризиків: A05 і межа термінів
У редакції :2025 інʼєкція (Injection) — категорія A05: вона опустилася з №3 на №5, але лишається однією з найтестованіших — якусь її форму перевіряли у 100% застосунків вибірки. Траєкторія позиції: №1 у 2013 і 2017, №3 станом на 2021, №5 у 2025; цифру завжди називайте з роком. Категорія обʼєднує XSS (висока частота, низький вплив, понад 30 тисяч ) і (низька частота, високий вплив, понад 14 тисяч CVE) — профілі навмисно різні. теж названі: ввід не валідується й не санітизується, непараметризовані виклики йдуть прямо в інтерпретатор, структура запиту й ворожі дані опиняються в одному рядку.
Тут же межа термінів, на якій легко посковзнутися. «Інʼєкція» — назва категорії ризику A05; «інʼєкційний дефект» — назва механізму класу. Перше відповідає на питання «куди це класифікувати», друге — «що саме зламано»; зводити їх в одне слово не варто. Інʼєкції в LLM у цей список не входять — вони винесені в окремий перелік OWASP для .
SQL-інʼєкція: класична, сліпа, часова
SQL-інʼєкція (SQL injection, ) — вставка часткового або повного SQL-запиту через дані, які клієнт передає застосунку. Умов дві, і друга обовʼязкова: непередбачені дані заходять із недовіреного джерела і використовуються для динамічної побудови запиту. Синтаксис програміста змішано з даними користувача в одному рядку, тож без екранування ввід починає читатися як SQL.
Наслідки задає джерело, а не уява: читання чутливих даних, їх зміна, адміністративні операції над СУБД аж до зупинки, доступ до файлу на сервері бази, подекуди й команди операційній системі. Оцінка за замовчуванням — високий вплив, ймовірність експлуатації — висока. Окремий сценарій: коли логін і пароль перевіряються поганим запитом, можна ввійти чужим користувачем, не знаючи пароля.
За каналом отримання даних розрізняють три класи — inband (тим самим каналом, яким зайшов пейлоад), out-of-band (іншим каналом) і inferential, він же сліпий (передачі даних немає, висновок будується з поведінки бази). Технік експлуатації гайд називає чотири: UNION (обʼєднати два запити, коли дефект у SELECT), булева, на помилках і із ; спільна вимога до всіх — синтаксично коректний запит. Осі дві, і плутати їх не варто: out-of-band — це канал, яким дані повертаються, а не техніка, якою запит ламають.
Коли вивід мовчить
(blind SQL injection) ставить базі питання «істина чи хиба» й читає відповідь із реакції застосунку; від звичайної вона відрізняється рівно способом отримання даних. Типовий її контекст — застосунок віддає узагальнені повідомлення про помилку, але вразливий код не полагоджено: загальна сторінка помилки дефекту не усуває, вона ховає індикатор. Різновидів два. Контентний: сторінка для «істини» відрізняється від сторінки для «хиби». Часовий (time-based): база робить паузу на задану кількість часу і лише тоді відповідає — і працює це навіть тоді, коли вміст сторінки не змінюється взагалі.
Дані добуваються посимвольно, окремим запитом на кожну літеру; затримку можна збільшувати, і чекати повної відповіді не обовʼязково. Часові функції є не лише в MySQL — джерело називає pg_sleep() у PostgreSQL і WAIT FOR DELAY у MS SQL. Побічний трофей — : різні функції поточної дати (now(), getdate(), sysdate()) видають конкретну базу. Для QA головне — : вердикт виносить різниця з базовою відповіддю або затримка, а не рядок помилки. Ручний прогін дуже витратний за часом, тому цей клас автоматизують.
NoSQL-інʼєкція: підсовують оператор, а не значення
(NoSQL injection) означена як небезпечна побудова обʼєктів запиту або рядків запиту з недовіреного вводу. Ключове слово — обʼєкт: мішень тут не лише текст команди, а й структура, з якої запит збирається. Оцінку шпаргалка OWASP не помʼякшує: інші моделі запиту й інші патерни розгортання створюють більше ризиків, ніж у реляційних базах, — саме більше, а не «інші за складом».
Вектор, якого в SQL немає, — оператор від клієнта: керовані клієнтом оператори ($where, $regex, $expr) мають бути заборонені, якщо не потрібні строго й не провалідовані, а сирі фрагменти JSON від клієнта не можна виконувати як запит. Єдиний конкретний приклад на сторінці — дозвіл надіслати { "$where": "this.balance > 0" }, і наслідків там два: віддалене виконання коду й важке навантаження на CPU. Другий небезпечний патерн — конкатенація вводу в рядки мови запитів або в shell-команди утиліт бази.
Захист: обʼєкти запиту драйвера замість побудови рядків, текстовий пошук через безпечні API драйвера з контрольованим вводом, вимкнення функцій, що виконують код на боці сервера. І пряме «не робіть»: покладатися лише на мережеві обмеження для захисту погано написаних запитів не можна. Для QA це означає перевіряти тіло запиту, а не лише поля форми — негативний набір містить і підміну структури JSON; індикатор при цьому може лежати не у відповіді, а в логах, тож підозрілі команди варто моніторити.
Командна інʼєкція та інші контексти
Командна інʼєкція (OS command injection) — виконання довільних команд на хостовій операційній системі через вразливий застосунок; з боку дефекту це побудова системної команди із зовні впливаного вводу без нейтралізації спецелементів. Вектори названо поіменно, і поля форми там лише перший пункт: форми, cookie, HTTP-заголовки. Команди виконуються з привілеями вразливого застосунку, а нехтування збільшує шкоду. У Unix команди розділяються крапкою з комою: додали ; і другу команду в кінець значення — вона виконається. Оточення процесу теж частина : system() і exec() користуються оточенням програми, тож відносний шлях до бінарника плюс нечищений $PATH дають вектор навіть без користувацького рядка в самій команді.
Звідси теза, що знімає найпоширеніше заперечення: кожна командна інʼєкція є водночас (argument injection), а наслідок тягнеться від розкриття інформації до критичного віддаленого виконання коду. «Команду захардкоджено» безпеки саме по собі не доводить.
Захист згори вниз. Головне — не викликати команди ОС узагалі: вбудовані бібліотечні функції названо дуже хорошою альтернативою. Якщо виклику не уникнути — два шари: параметризація структурним механізмом розділення даних і команди, а поверх — валідація окремо для команди (список дозволених) і окремо для аргументів ( зі списком дозволених символів і межею довжини, без метасимволів і пробілів). Позитивна модель тут не стильова вподоба: законні символи перелічити значно легше за незаконні. Дрібниця з POSIX: перший --, що не є аргументом опції, приймається як роздільник кінця опцій, тож curl -- $url запобігає інʼєкції аргументу. І мовна механіка, яку плутають: у Java Runtime.exec шел не викликає взагалі, тоді як system() у C передає свої аргументи /bin/sh на розбір.
LDAP і решта мішеней
(LDAP injection) — той самий механізм у каталозі: інструкції будуються з користувацького вводу й змінюються техніками, схожими на SQL-інʼєкцію; наслідок — права неавторизованим запитам і зміна вмісту дерева. Клас поширений із двох причин, і перша важлива для всієї глави: безпечних параметризованих інтерфейсів LDAP-запиту бракує; друга — на LDAP широко тримається автентифікація. Тому захистів тут два інші: екранувати правильною функцією кодування або взяти фреймворк, який екранує сам. Контекстів вставки два, з різним екрануванням, — фільтр пошуку (префіксна, вона ж польська, нотація) і DN, , чий вичерпний перелік спецсимволів включає провідні та кінцеві пробіли. застосовна, але нормалізація передує валідації. І «у нас bind-автентифікація» вердиктом не є: джерело називає два обходи — анонімне зʼєднання й unauthenticated bind.
Решта карти коротко: XPath-запити стоять у тому самому переліку мішеней; вразливими бувають і SOAP- та REST-запити, наслідок там — витяг даних або обхід контролю; у скриптових мовах вектор дає eval-подібний виклик; мережеві демони (SMTP, IMAP, FTP) приймають ввід просто в потік обміну.
Параметризований запит і чотири варіанти OWASP
(parameterized query) змушує спершу визначити весь код SQL, а кожен параметр передати пізніше. Наслідок сформульовано без помʼякшень: база завжди відрізнятиме код від даних, хоч би що подав користувач, а (prepared statement) не дає змінити намір запиту, навіть якщо у ввід вставили SQL-команди. Механізм — (bind variables): ними базі повідомляють, що входи цього динамічного SQL є «даними», а не можливим кодом. Класичний пейлоад тут нічого не ламає: tom' or '1'='1 шукатиметься як імʼя користувача, що буквально дорівнює всьому цьому рядку.
Дві пастки видно тільки в коді. Перша: параметризація має бути серверною — багато клієнтських бібліотек «параметризують» так, що склеюють рядок і надсилають серверу вже сирий запит. Друга: ідентифікатори параметром не підставляються — імена бази, схеми, таблиці чи стовпця через плейсхолдер передати не можна; саме там (плюс напрям сортування) доречні валідація або переробка запиту, а значення мають приходити з коду, а не з користувацьких параметрів.
// node-postgres: текст запиту йде незміненим, значення підставляє сервер
await client.query('SELECT id, email FROM users WHERE email = $1', [email]);
// А так — ні: рядок склеєно ще до бази
await client.query(`SELECT id, email FROM users WHERE email = '${email}'`);
// Імʼя таблиці плейсхолдером не передати — беремо його з коду, не з параметра
const table = ALLOWED_TABLES[name];
Чотири варіанти й межі кожного
Шпаргалка запобігання перелічує чотири варіанти, і порядок не декоративний: 1 — підготовлені інструкції з параметризованими запитами; 2 — правильно побудовані ; 3 — валідація за списком дозволеного; 4 — КАТЕГОРИЧНО НЕ РЕКОМЕНДОВАНО: екранування всього користувацького вводу. Сусідня шпаргалка додає: SQL-інʼєкції найкраще запобігати параметризованими запитами — «найкраще», а не «єдиним способом».
Збережені процедури — місце, де сам OWASP говорить двома голосами. Шпаргалка запобігання: підхід має той самий ефект, що параметризація, доки процедури реалізовані безпечно, тобто без небезпечної динамічної генерації SQL усередині. Сторінка www-community того ж OWASP жорсткіша: процедури запобігають деяким типам атак, але не захищають від багатьох інших, а обмеження обходяться. Гайд тестування додає третій бік: динамічний SQL усередині процедури вимагає санітизації, інакше зловмисний SQL виконається просто в ній. Тож «у нас логіка в збережених процедурах» аргументом не є.
Валідація за списком дозволеного відповідає за місця, де привʼязати змінну неможливо, і як другорядний захист рекомендована завжди. Але повною вона не буває: спецсимволи багатьом застосункам потрібні законно, а вільні текстові поля вона не закриває. з переліку захистів випадає зовсім — такі списки «поцятковані лазівками».
Екранування — місце, де два канонічні джерела дають протилежний пріоритет, і глава сторони не обирає. OWASP ставить його останнім із позначкою STRONGLY DISCOURAGED: методологія крихка, і гарантувати, що вона запобіжить усім інʼєкціям у всіх ситуаціях, шпаргалка не може; ручне екранування «може допомогти, але не зробить ваш застосунок захищеним». MITRE у CWE-89 навпаки: правильне , екранування й квотування — «найдієвіше розвʼязання», а валідація дає лише певний ешелонований захист. Предмет у цих формулювань різний: MITRE говорить про механізм (правильне екранування в місці виводу), шпаргалка — про стратегію (ручне екранування всього входу як спосіб будувати застосунок); жодне з джерел цієї відмінності саме не проговорює, тож обидва наводяться з атрибуцією. Як запасний варіант екранування лишається дозволеним і в OWASP — але під конкретний інтерпретатор.
І дві межі самої ідеї: у LDAP безпечних параметризованих інтерфейсів бракує, а в командах ОС «параметризація» означає структурний механізм розділення, а не привʼязані змінні. Мінімізація привілеїв акаунтів бази зменшує шкоду, а не дефект.
Тестування: пейлоади, індикатори, автоматизація
Спершу інвентаризація точок вводу. Потрібен список усіх полів, значення яких можуть потрапити в запит, включно з прихованими полями POST-запитів; заголовки й cookie теж у списку. Мапа ризиків формулює ширше: параметри, заголовки, URL, cookie, JSON, SOAP і XML-входи.
Перші проби. Найперший тест — одинарна лапка ' або крапка з комою ;: лапка є термінатором рядка в SQL, і якщо її не фільтрують, запит стає некоректним. Далі пробують роздільники коментарів (--, /* */), ключові слова AND і OR, а також рядок там, де очікується число. Канонічний приклад показує суть: завжди істинна умова (OR 1=1) змушує запит повернути значення — і система автентифікує користувача, не знаючи ні логіна, ні пароля; у мапі ризиків це виглядає як підміна параметра id на ' OR '1'='1.
Індикатори. Дивитися треба не тільки на екран: помилка часто лежить у HTML- або JavaScript-коді відповіді й користувачеві не показується. Просте 500 Server Error чи кастомна сторінка помилки — сигнал переходити до сліпих технік, а не висновок «не вразливе». Дисципліна прогону: одне поле за раз, решта параметрів незмінна. Цілі тесту — знайти точки інʼєкції й оцінити серйозність та рівень доступу, який через них досяжний.
// Playwright: пейлоад не має змінювати ні код, ні форму відповіді
const base = await request.get('/api/orders', { params: { id: '42' } });
const probe = await request.get('/api/orders', { params: { id: "42'" } });
expect(probe.status()).toBe(base.status());
expect(await probe.text()).not.toMatch(/sql|syntax error|sqlstate/i);
Автоматика і її сліпа зона. Автоматизований (у безпековій рамці — , Static Application Security Testing) розбирає код, не виконуючи його, і CWE-89 знаходить часто, зменшуючи хибні спрацювання аналізом потоків даних. Але він може не побачити виклики через власні API-функції чи сторонні бібліотеки, що звертаються до SQL опосередковано, — це хибнонегативні результати, тож чистий звіт доказом не є. Добирають динамічними техніками: , тестуванням на стійкість, внесенням несправностей. Асиметрію класу названо прямо: інʼєкційні дефекти легко виявити ревʼю коду й важче — тестуванням, а сканери й фазери допомагають і атакувальнику.
-сканер: два режими. — окремий додаток, який перевіряє повідомлення (HTTP, WebSocket), пропущені крізь ZAP або надіслані ним; воно жодним чином не змінює відповіді й вважається безпечним. Активне сканування застосовує до цілей відомі атаки, тобто є справжньою атакою: дока попереджає про можливу реальну шкоду функціональності сайту й даним — тільки свій стенд і тільки з дозволом. Прогін у CI, гейти й місце у — тема окремої глави про автоматизацію security-перевірок наприкінці розділу.
Типові помилки
- «Помилок ми не показуємо — інʼєкції немає» → виглядає як захист, а насправді узагальнена сторінка помилки лише ховає індикатор: саме такий контекст названо типовим для сліпої інʼєкції.
- «Спецсимволи фільтруються» → виглядає як закритий дефект, а насправді валідація навіть за списком дозволеного повним захистом не є: спецсимволи багатьом застосункам потрібні законно.
- «У нас збережені процедури» → виглядає як параметризація, а насправді еквівалентність діє лише без небезпечної динамічної генерації SQL усередині.
- «Плейсхолдери в коді є» → виглядає як параметризований запит, а насправді частина клієнтських бібліотек склеює рядок ще до відправки: підстановку робить сервер, і перевіряти треба саме там.
- «Команда захардкоджена, підставляється лише аргумент» → виглядає як безпечний виклик, а насправді кожна командна інʼєкція є водночас інʼєкцією аргументів.
- «Це NoSQL, тут інʼєкцій не буває» → виглядає як властивість технології, а насправді ризиків там більше, а вектор із оператором від клієнта в SQL узагалі відсутній.
- «Сканер пройшов чисто» → виглядає як доказ, а насправді статика не бачить викликів через власні обгортки й сторонні бібліотеки, а пасивний прохід проксі нічого до застосунку не досилає — він лише читає наявний трафік.
Підсумок
- Інʼєкція — це один механізм, а не десять різних багів. Недовірені дані доходять до інтерпретатора, і те, що задумувалося як значення, потрапляє в площину керування. Змінюється мішень і синтаксис пейлоада — логіка перевірки лишається та сама.
- Категорія і механізм — різні поняття. «Інʼєкція» — назва категорії A05 у Top 10:2025, де вона стоїть пʼятою й обʼєднує XSS із SQL-інʼєкцією; «інʼєкційний дефект» — назва самого механізму.
- Справжній захист — структурне розділення даних і команди. Параметризований запит визначає весь код першим і передає значення окремо; збережені процедури, валідація за списком дозволеного й екранування — три інші варіанти OWASP, кожен зі своїм застереженням, а щодо екранування два канонічні джерела дають протилежний пріоритет.
- Оракулом часто є поведінка, а не текст. Різниця з базовою відповіддю або затримка працюють там, де помилок не видно, тож перевірка будується на порівнянні.
- Точки вводу ширші за форму, а чистий скан не є доказом. Приховані поля, заголовки, cookie, JSON — усе це вектори; статика має хибнонегативні результати, а активне сканування є справжньою атакою й потребує дозволу.
Можливі питання
- «Що таке SQL-інʼєкція і чому вона взагалі можлива?» — перевіряють механізм, а не завчене означення. Сильна відповідь говорить про змішування синтаксису й даних в одному рядку та про відсутність межі між площинами керування й даних.
- «Чим сліпа інʼєкція відрізняється від звичайної?» — на розуміння оракула. Чекають, що різниця рівно в способі отримання даних і що вердикт виносить різниця відповідей або затримка; плюс бали за пояснення, чому кастомна сторінка помилки дефекту не закриває.
- «Як ти перевірятимеш поле на інʼєкцію?» — питання про процедуру: інвентаризація точок вводу разом із прихованими полями, заголовками й cookie, перші проби, дисципліна «одне поле за раз», опис індикаторів.
- «Параметризовані запити чи екранування?» — пастка на однозначну відповідь. Сильний кандидат називає параметризацію основним захистом і знає, що щодо екранування каталог CWE й шпаргалка OWASP розставляють пріоритети по-різному.
- «У нас MongoDB — інʼєкція нам не загрожує?» — перевіряють, чи привʼязане знання лише до SQL. Правильна відповідь: небезпечно будується сам обʼєкт запиту, а головний вектор — оператор або фрагмент JSON від клієнта.
- «Чим командна інʼєкція відрізняється від інʼєкції коду?» — на точність меж: власний код тут не потрібен, розширюється наявна функція застосунку, і команда виконується з його привілеями.
- «Сканер безпеки не знайшов нічого. Реліз?» — питання про межі автоматики: хибнонегативні результати статики й різниця пасивного та активного сканування.
Джерела
Механізм: код і дані в одному рядку
- OWASP Cheat Sheet — Injection Prevention — означення дефекту й перелік мішеней.
- OWASP www-community — SQL Injection — площини керування й даних, межі між ними SQL не проводить.
- CWE-89 — Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection') — той самий дефект з боку коду.
- OWASP www-community — Command Injection — межа між інʼєкцією коду й командною.
Інʼєкція в мапі ризиків: A05 і межа термінів
- OWASP Top 10:2025 — Injection — категорія A05, падіння з №3 на №5, частка застосунків, профілі XSS і SQLi, передумови.
- OWASP Cheat Sheet — Query Parameterization — попередні позиції: №1 у 2013 і 2017, №3 у 2021.
SQL-інʼєкція: класична, сліпа, часова
- OWASP www-community — SQL Injection — означення, дві умови, наслідки, високий вплив, обхід автентифікації.
- CWE-89 — Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection') — скорочення SQLi, висока ймовірність експлуатації.
- OWASP WSTG — 4.7.5 Testing for SQL Injection (WSTG-INPV-05) — три класи за каналом, чотири техніки, затримка як оракул.
- OWASP www-community — Blind SQL Injection — контентний і часовий різновиди, посимвольне добування, відбиток СУБД.
- OWASP Cheat Sheet — Injection Prevention — «частковий або повний запит» і клас inferential.
NoSQL-інʼєкція: підсовують оператор, а не значення
- OWASP Cheat Sheet — NoSQL Security — означення через обʼєкти запиту, більші ризики проти реляційних баз, оператори від клієнта, приклад
$where, захисти й моніторинг.
Командна інʼєкція та інші контексти
- OWASP www-community — Command Injection — вектори, привілеї застосунку, роздільник команд,
$PATH, позитивна модель. - OWASP — OS Command Injection Defense Cheat Sheet — інʼєкція аргументів, від викликів ОС, два шари, роздільник
--,Runtime.execпротиsystem(). - OWASP Cheat Sheet — LDAP Injection Prevention — дві причини поширеності, два контексти екранування, пробіли в переліку DN, порядок нормалізації, обходи bind.
- OWASP Cheat Sheet — Injection Prevention — XPath, SOAP і REST, eval, мережеві демони.
Параметризований запит і чотири варіанти OWASP
- OWASP Cheat Sheet — SQL Injection Prevention — означення параметризації, приклад
tom' or '1'='1, чотири варіанти з позначкою STRONGLY DISCOURAGED, умова «implemented safely», привілеї акаунтів. - OWASP Cheat Sheet — Query Parameterization — bind-змінні, пастка клієнтської параметризації, «найкраще запобігати параметризованими запитами».
- node-postgres — Queries — текст іде незміненим, підстановка на сервері, параметри не працюють для ідентифікаторів.
- OWASP Cheat Sheet — Injection Prevention — підготовлені інструкції проти зміни наміру запиту, екранування під конкретний інтерпретатор.
- CWE-89 — Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection') — «Parameterization» як стратегія й формулювання MITRE про найдієвіше розвʼязання.
- OWASP www-community — SQL Injection — жорсткіший вердикт про збережені процедури, лазівки deny-list, межі ручного екранування.
- OWASP WSTG — 4.7.5 Testing for SQL Injection (WSTG-INPV-05) — динамічний SQL усередині збереженої процедури.
- OWASP Cheat Sheet — LDAP Injection Prevention — брак безпечних параметризованих інтерфейсів LDAP.
- OWASP — OS Command Injection Defense Cheat Sheet — «параметризація» для команд ОС і межа екранування аргументу.
Тестування: пейлоади, індикатори, автоматизація
- OWASP WSTG — 4.7.5 Testing for SQL Injection (WSTG-INPV-05) — інвентаризація точок вводу, перші проби, помилка в коді відповіді, «одне поле за раз», цілі тесту.
- OWASP Top 10:2025 — Injection — перелік місць перевірки, ревʼю коду з фазингом, приклад підміни
id. - CWE-89 — Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection') — що статика знаходить і чого не бачить, динамічні техніки.
- CWE-918 — Server-Side Request Forgery (SSRF) — назва методу: статичний аналіз без виконання коду зветься SAST.
- OWASP Cheat Sheet — Injection Prevention — «легко в коді, важче тестуванням», сканери працюють в обидва боки.
- OWASP ZAP — Passive Scan — пасивна перевірка як окремий додаток, її матеріал — HTTP і WebSocket крізь ZAP.
- ZAP – Getting Started — пасивний скан безпечний, активний є справжньою атакою з реальною шкодою.
Що таке інʼєкція і чому вона взагалі можлива?
трапляється тоді, коли дані від користувача доїжджають до якогось інтерпретатора — бази, шела, каталогу — вже вклеєними в текст команди. Механізм описують через рух даних, а не через технологію: недовірений ввід потрапляє туди, де його розбирають як частину інструкції. Причина проста і неприємна: у рядку, який отримує інтерпретатор, немає жодної позначки, де закінчується синтаксис розробника й починається значення користувача. Тому спецсимвол у полі даних переносить фрагмент вводу в площину керування (control plane) — туди, де його ніхто не планував бачити. Мова запитів такого кордону з площиною даних (data plane) сама не тримає, тож розсудити «команда це чи текст» нема кому. З боку коду те саме описує -89: команда збирається з входу, на який впливають ззовні, а спецелементи, здатні змінити задум інструкції, ніхто не нейтралізує. Практичний висновок для QA: інʼєкція — це не десяток різних багів, а один дефект із різними мішенями, тож логіка перевірки скрізь однакова.
Де інʼєкція стоїть в OWASP Top 10 і що входить у цю категорію?
У редакції 2025 року інʼєкція — це A05, тобто пʼята позиція. Історія руху така: перше місце у 2013 і 2017, третє у 2021, пʼяте у 2025 — тому цифру завжди варто називати разом із роком, інакше відповідь звучить як завчена. Падіння в рейтингу не означає, що тема зникла: якусь форму інʼєкції перевіряли в усіх без винятку застосунках вибірки. Усередині категорії стоять два дуже різні профілі: XSS — часта, але з нижчим впливом і понад тридцятьма тисячами , і — рідша, зате з високим впливом і понад чотирнадцятьма тисячами CVE. теж перелічені прямо: ввід ніхто не перевіряє й не чистить, виклики йдуть в інтерпретатор без параметрів, а структура запиту й ворожі дані живуть в одному рядку.
Що таке SQL-інʼєкція і які умови мають збігтися, щоб вона спрацювала?
Це вставка SQL-запиту — часткового або цілого — через ті дані, що клієнт віддає застосунку. Умов дві, і потрібні обидві: по-перше, у застосунок заходять непередбачені дані з недовіреного джерела, по-друге — саме ці дані беруть участь у динамічній побудові запиту. Якщо друга умова не виконується (значення їде окремо від тексту команди), перша сама по собі нічого не ламає. Коли ж синтаксис розробника й ввід користувача змішані в одному рядку без екранування, база починає читати ввід як SQL. Ця пара умов зручна ще й тим, що з неї одразу видно напрямок фіксу: прибирають не «погані символи», а сам факт склеювання.
Наскільки серйозна SQL-інʼєкція за наслідками?
Оцінка тут не «залежить»: вплив за замовчуванням високий, а ймовірність експлуатації теж висока. Через дефект можна прочитати чутливі дані, змінити їх, виконати адміністративні операції над СУБД аж до її зупинки, дістатися файлу на сервері бази, а подекуди — і віддати команду операційній системі. Тобто масштаб починається з витоку однієї таблиці й закінчується контролем над інфраструктурою навколо бази. Для тікета це означає, що серйозність не варто занижувати до «показує зайві дані»: у звіті краще описати не лише те, що вдалося витягти, а й рівень доступу, який через цю точку принципово досяжний. Саме оцінка досяжного доступу — одна з двох задач тесту на інʼєкцію, поряд із пошуком самих точок.
Як через SQL-інʼєкцію входять у чужий акаунт, не знаючи пароля?
Коли форма логіна перевіряє пару «логін-пароль» склеєним запитом, підставлена завжди істинна умова робить умову добору беззмістовною. Запит повертає рядок, застосунок бачить «збіг знайдено» і автентифікує користувача, хоча правильного пароля ніхто не вводив. Канонічна проба виглядає як ' OR '1'='1 у значенні параметра — та сама ідея працює і при підміні id у запиті, коли треба не ввійти, а витягти зайві рядки. Важливо, що для цього не потрібно вгадувати жодних облікових даних: ламається не пароль, а логіка добору. Тому негативний набір на форму логіна вартий окремої уваги — це найдешевша демонстрація дефекту, яку зрозуміє і нетехнічний читач тікета.
Чим сліпа інʼєкція відрізняється від звичайної?
Різниця рівно в одному: у способі отримати дані. Механізм дефекту той самий, змінюється лише канал, яким відповідь доходить до того, хто перевіряє. У звичайному випадку дані повертаються тим самим каналом, яким зайшов пейлоад; у сліпому варіанті застосунок нічого не віддає, і висновок будують із поведінки. База відповідає на питання «істина чи хиба», а тестувальник читає відповідь із реакції застосунку. Різновидів два: контентний, коли сторінка для істини й сторінка для хиби відрізняються, і часовий, коли база просто мовчить задану кількість секунд перед відповіддю. Головне слово тут — : вирок виносить або розбіжність із базовою відповіддю, або зайві секунди на секундомірі, а зовсім не текст помилки на екрані.
Що таке часова інʼєкція і коли вона єдиний доступний варіант?
Часова (time-based) інʼєкція змушує базу зробити паузу перед відповіддю, і саме тривалість відповіді стає сигналом. Її сила в тому, що вона працює навіть тоді, коли вміст сторінки не змінюється взагалі: тіло однакове, код 200 однаковий, різна тільки арифметика секундоміра. Функції є в різних СУБД — pg_sleep() у PostgreSQL, WAIT FOR DELAY у MS SQL, — тож прийом не привʼязаний до однієї бази. Заодно та сама механіка здає : функція поточної дати в кожної своя — now(), getdate(), sysdate(), — і по тому, котра з них відпрацювала, видно, з чим маєш справу. Дані добуваються посимвольно, окремим запитом на кожну літеру, тож повного дампа руками ніхто не робить — цей клас автоматизують, бо ручний прогін коштує надто багато часу.
Що таке NoSQL-інʼєкція і чим її головний вектор відрізняється від SQL?
Її означують як небезпечну побудову обʼєктів запиту або рядків запиту з недовіреного вводу — і ключове слово тут «обʼєкт». Ціллю виявляється не сам текст команди, а конструкція, з якої запит складають, тому підміняють не вміст поля, а його тип чи ключ. Звідси й вектор, якого в реляційному світі просто немає: оператор від клієнта. Керовані клієнтом $where, $regex, $expr тримають під забороною, доки не доведено, що вони справді потрібні й провалідовані, а сирий фрагмент JSON, надісланий клієнтом, не має виконуватися як запит узагалі. Наочний приклад — дозвіл надіслати { "$where": "this.balance > 0" }: наслідків тут одразу два, віддалене виконання коду й важке навантаження на процесор. Другий небезпечний патерн той самий, що всюди, — конкатенація вводу в рядок мови запитів або в shell-команду службової утиліти бази.
«У нас MongoDB, тут інʼєкцій не буває» — що відповісти?
Що це властивість уявлення про технологію, а не самої технології. Канонічна шпаргалка оцінює це рівно навпаки: через власну модель запиту й власні патерни розгортання документні сховища накопичують не «інакших за складом», а просто більше, ніж реляційні. Форма захисту теж своя: запит збирають обʼєктом драйвера, а не рядком; текстовий пошук пускають через безпечні API драйвера з контрольованим вводом; серверне виконання коду вимикають. Окремо сказано «ні» ідеї закрити погано написані запити самими лише мережевими обмеженнями. Для тестування з цього випливає конкретика: перевіряти треба тіло запиту, а не тільки поля форми, а в негативний набір класти підміну структури JSON. І ще одна пастка: індикатор може взагалі не зʼявитися у відповіді, а осісти в логах, тож підозрілі команди варто моніторити окремо.
Чим командна інʼєкція відрізняється від інʼєкції коду?
Інʼєкція коду дає додати власний код, який виконає застосунок. У власний код не потрібен: розширюється наявна функція, яка й так виконує системні команди, — до неї просто дописують ще одну. У Unix для цього достатньо крапки з комою: додав ; і другу команду в кінець значення, і вона виконається. Виконуються ці команди з привілеями вразливого застосунку, тож нехтування принципом прямо збільшує шкоду. Вектори не обмежені формою: поіменно названі форми, cookie та HTTP-заголовки. Наслідки тягнуться від розкриття інформації до критичного віддаленого виконання коду.
«Команда в нас захардкоджена, зовні приходить лише аргумент» — це безпечно?
Саме по собі — не доказ. Теза, яка знімає це заперечення, сформульована жорстко: кожна командна інʼєкція є водночас , тож підстановка «лише аргументу» не виводить виклик із класу ризику. , який змінює поведінку утиліти, робить свою справу без жодної крапки з комою. на цьому не закінчується — у неї входить і оточення процесу: system() та exec() успадковують оточення програми, тож бінарник, викликаний відносним шляхом при неочищеному $PATH, дає вектор навіть там, де користувацького рядка в команді не буває взагалі. Є й дрібниця з POSIX, яку варто знати: за десятою настановою перше -- поза позицією аргумента опції читається як кінець опцій, тому запис на кшталт curl -- $url знімає саме інʼєкцію аргументу. І мовна механіка, яку регулярно плутають: у Java Runtime.exec шела не викликає взагалі, тоді як system() у C віддає свої аргументи /bin/sh на розбір.
Як правильно захищатися від командної інʼєкції?
Найкращий варіант — не викликати команди операційної системи взагалі: вбудовані бібліотечні функції названі дуже хорошою альтернативою, і ця порада стоїть першою не випадково. Якщо виклику не уникнути, будують два шари. Перший — параметризація, але тут це означає структурний механізм розділення даних і команди, а не привʼязані змінні з світу SQL. Другий — валідація, причому окремо для команди й окремо для аргументів: для команди список дозволених, для аргументів із переліком дозволених символів і межею довжини, без метасимволів і пробілів. Позитивна модель тут не стильова вподоба, а арифметика: законні символи перелічити значно легше, ніж спробувати перерахувати всі незаконні.
Як параметризований запит захищає і що саме він робить із класичним пейлоадом?
Він змінює порядок дій: спершу визначається весь код SQL, і лише потім у готову інструкцію передаються значення. Наслідок сформульовано без помʼякшень — розділення коду й даних тримається за будь-якого вводу, а намір лишається тим самим, навіть якщо в поле поклали готову SQL-команду. Технічний механізм — : вони позначають входи динамічного SQL саме як дані, а не як потенційний код. Класична проба на такому запиті виглядає безглуздо: tom' or '1'='1 шукатиметься як імʼя користувача, буквально рівне всьому цьому рядку, і не знайдеться. Саме тому параметризацію називають основним захистом — не тому, що вона фільтрує щось краще, а тому, що вона знімає передумову дефекту: код і дані більше не їдуть одним рядком.
У коді є плейсхолдери. Чи достатньо цього, щоб вважати запит параметризованим?
Ні, і тут дві пастки, які видно лише в коді. Перша: параметризація має бути серверною. Частина клієнтських бібліотек «параметризує» так, що склеює рядок у себе і надсилає базі вже готовий сирий запит — плейсхолдер у коді є, розділення немає. Друга: ідентифікатори через плейсхолдер не передаються взагалі. Імена бази, схеми, таблиці чи стовпця (а поруч із ними й напрям сортування) параметром не підставляються — тут доречні або список дозволеного, або переробка самого запиту, а джерелом такого імені має бути код застосунку, а не поле, яке заповнює користувач. Тому на ревʼю дивляться не на наявність символів $1 чи ?, а на те, хто фактично збирає фінальний текст.
«У нас уся логіка в збережених процедурах» — це аргумент?
Не є, і саме на цьому питанні добре видно . Шпаргалка запобігання справді прирівнює ефект процедури до ефекту параметризації — але рівно доти, доки її реалізовано безпечно, тобто доки всередині не генерується динамічний SQL. Сторінка www-community того самого OWASP формулює жорсткіше: частину типів процедури зупиняють, від багатьох інших не рятують, а накладені ними обмеження мають обхідні шляхи. Гайд тестування додає третій бік: якщо всередині процедури будується динамічний SQL, його треба санітизувати, інакше зловмисний SQL виконається просто в ній. Тобто сама по собі процедура нічого не гарантує — гарантує те, як побудовано запит усередині, і саме туди варто дивитися.
Чому валідація за списком дозволеного не закриває тему повністю?
Тому що роль у неї службова: закривати ті шматки запиту, куди bind-змінну не поставиш, і супроводжувати основний захист другим ешелоном — рекомендують її завжди, повною вона не буває ніколи. Дві причини конкретні: спецсимволи багатьом застосункам потрібні законно (апостроф у прізвищі — не атака), а вільні текстові поля вона не закриває взагалі. з переліку захистів випадає зовсім: такі списки називають поцяткованими лазівками, і будувати на них рішення не варто. Практичний висновок: список дозволеного — це шар навколо параметризації, а не її заміна. Так само й мінімізація привілеїв акаунтів бази: вона зменшує шкоду від успішної атаки, але сам дефект лишається на місці.
Параметризовані запити чи екранування — що правильно відповісти?
Правильно — не давати однозначної відповіді, бо це пастка. Основний захист — параметризація: у переліку OWASP підготовлені інструкції стоять першим варіантом, а екранування всього користувацького вводу — четвертим, із позначкою STRONGLY DISCOURAGED; методологію називають крихкою й прямо кажуть, що гарантувати запобігання всім інʼєкціям у всіх ситуаціях шпаргалка не може. Але каталог CWE-89 розставляє акценти навпаки: правильне , екранування й квотування він називає найдієвішим розвʼязанням, а валідації відводить роль ешелонованого захисту. Суперечність тут радше в предметі, ніж по суті: MITRE говорить про механізм — коректне екранування в місці виводу, — а шпаргалка про стратегію будувати застосунок на ручному екрануванні всього входу. Жодне з джерел цієї різниці саме не проговорює, тож сильна відповідь називає обидва пріоритети з атрибуцією, а не вдає, ніби джерело тут одне. Зовсім екранування OWASP не викреслює: за браку параметризованого API воно лишається запасним ходом — з умовою, що синтаксис береться під той інтерпретатор, у який поїде рядок.
Чому в LDAP не можна просто «зробити як із SQL»?
Бо того, що робить основний захист у SQL, там бракує: безпечних параметризованих інтерфейсів LDAP-запиту просто немає. Це перша з двох причин, чому клас узагалі поширений; друга — на LDAP широко тримається автентифікація, тож мішень цінна. Тому основних захистів тут два інші: або підібрати коректну функцію LDAP-кодування під контекст, або взяти фреймворк, який екранує сам. Контекстів вставки два, і екранування в них різне: фільтр пошуку записують у префіксній (польській) нотації, а DN — — має власний вичерпний список спецсимволів, до якого потрапили навіть пробіли на початку й у кінці значення. Список дозволеного тут теж працює, але порядок кроків важливий: нормалізація йде перед валідацією, інакше перевіряють не те, що потрапить у запит. І окремо: «у нас bind-автентифікація» вердиктом не є — обходи названі поіменно, це анонімне зʼєднання й unauthenticated bind.
Як ти перевірятимеш поле на інʼєкцію? Опиши процедуру.
Починається все не з пейлоада, а з інвентаризації точок вводу: у список ідуть усі поля, чиє значення має шанс доїхати в запит, — разом із прихованими полями POST, заголовками й cookie. Ширший перелік місць звучить так: параметри, заголовки, URL, cookie, JSON, SOAP- і XML-входи. Далі — перші проби: одинарна лапка або крапка з комою, потім роздільники коментарів (--, /* */), ключові слова AND та OR, а також рядок там, де очікується число. Лапка перша не випадково: у SQL вона закриває рядковий літерал, тож нефільтрована ламає синтаксис склеєного запиту — і сама ця поломка вже сигнал. Дисципліна прогону проста, але її часто порушують: одне поле за раз, решта параметрів незмінна, інакше незрозуміло, що саме дало реакцію. Індикатори дивляться не тільки на екрані — помилка часто лежить у коді відповіді; а якщо помилок не видно взагалі, це не «чисто», а привід переходити до порівняння відповідей і проб із затримкою. Ціль усього прогону — знайти точки інʼєкції й оцінити, який рівень доступу через них досяжний.
Сканер безпеки нічого не знайшов. Релізимо?
Ні — і тут важливо пояснити, чого саме сканер не бачить. () читає код без запуску, і CWE-89 йому дається добре: сучасні інструменти ще й тримають хибні спрацювання низькими за рахунок аналізу потоків даних. Сліпа зона в іншому: якщо до SQL звертаються опосередковано — через власну обгортку або сторонню бібліотеку, — виклик може взагалі не потрапити в поле зору. Це хибнонегативні результати, тому порожній звіт нічого не спростовує; добирають динамікою — , перевіркою на стійкість, внесенням несправностей. Варто назвати й асиметрію класу: ревʼю коду бачить такий дефект легше, ніж прогін тестів, а сканер із фазером однаково зручні обом сторонам. Окремо варто розрізняти режими -сканера: лише читає повідомлення, що йдуть крізь інструмент, відповідей не змінює й вважається безпечним, тоді як активне застосовує до цілі відомі атаки, тобто є справжньою атакою — з ризиком реальної шкоди функціональності й даним, тільки на своєму стенді й тільки з дозволом.
Три кейси з робочого життя QA: як відрізнити «поле фільтрує лапку» від «поле не вразливе», як побудувати для сліпої , коли екран мовчить, і як прочитати негативний набір для NoSQL-, де підміняють не значення, а структуру. Скрізь — що дивитися і чому саме це, а не сусіднє.
Кейс 1. Проба лапкою: реакція є, вразливості може й не бути
Тестувальник кинув у поле пошуку одинарну лапку, отримав 500 — і вже пише тікет «SQL-інʼєкція». Питання, яке варто поставити перед тікетом: що саме довела ця проба? Лапка — термінатор рядка в SQL, і якщо її не фільтрують, склеєний запит стає синтаксично некоректним. Тобто 500 доводить, що ввід доїжджає в запит несанітизованим, — це сильний сигнал, але ще не експлуатація. Наступний крок — не святкувати, а показати керованість: та сама точка має або пустити коректний пейлоад, або відреагувати на істинну й хибну умову по-різному.
| Проба | Реакція | Що це доводить |
|---|---|---|
' (одна лапка) | 500 або помилка синтаксису | ввід потрапляє в запит несанітизованим — сигнал, не вирок |
'' (дві лапки) | сторінка як на базовому запиті | лапка справді ламала синтаксис, а не збіг |
' OR '1'='1 у логіні | вхід без правильного пароля | логіка добору керована ззовні — оце вже експлуатація |
| ті самі проби на параметризованому полі | завжди базова відповідь, помилок нема | код і дані розділені — точка не вразлива |
Ключове читання таблиці: перший рядок сам по собі не є доказом вразливості, а останній сам по собі не є доказом захисту, поки не спробувано пейлоад. Зелений функціональний тест тут не значить нічого — форма працює, а поле дає читати зайве.
import { test, expect } from '@playwright/test';
// Проба не має ні ламати відповідь, ні змінювати її форму.
// Різниця між base і probe — привід копати, а не зелене «все гаразд».
test('поле пошуку: лапка не змінює код і форму відповіді', async ({ request }) => {
const base = await request.get('/api/search', { params: { q: 'laptop' } });
const probe = await request.get('/api/search', { params: { q: "laptop'" } });
// однаковий статус: сплеск у 500 на пробі — сигнал несанітизованого вводу
expect(probe.status(), 'лапка не мусить валити запит').toBe(base.status());
// у відповіді не має протікати діагностика СУБД
expect(await probe.text()).not.toMatch(/sql|syntax|sqlstate|odbc|pg::/i);
});
Що дивитися і чому:
500на лапці — сигнал, не вирок. Він каже, що ввід доїхав у запит сирим. Доказом експлуатації його робить лише наступний крок: керована реакція на пейлоад.- Діагностика СУБД у тілі відповіді — окрема знахідка. Рядок на кшталт
SQLSTATEчиpg::SyntaxErrorне показується на екрані, але лежить у відповіді; його витік сам по собі вартий тікета, бо дає відбиток бази. - Однаковий статус на base і probe — не «нудний асерт». Саме розбіжність тут відкриває розмову; тому пейлоад підбирають так, щоб у здоровому застосунку він нічого не змінював.
Кейс 2. Сліпа інʼєкція: коли екран мовчить, оракулом стає час
Ендпоінт віддає узагальнену сторінку помилки — жодних SQLSTATE, жодної діагностики. Спокуса написати «не вразливе» велика й хибна: загальна сторінка ховає індикатор, а не закриває дефект. Коли вміст відповіді не змінюється взагалі, лишається часовий оракул: попросити базу помовчати задану кількість секунд і виміряти, чи вона послухалась. Дисципліна тут така сама, як усюди, — одне поле за раз, решта параметрів незмінна, а вердикт виносить різниця з базовим часом, а не окреме абсолютне число.
import { test, expect } from '@playwright/test';
// Оракул часової інʼєкції: якщо керована затримка відтворюється,
// база виконує підставлений вираз. Вміст відповіді при цьому не змінюється.
test('часовий оракул: керована затримка відтворюється', async ({ request }) => {
const t0 = Date.now();
await request.get('/api/orders', { params: { id: '42' } });
const baseMs = Date.now() - t0;
const t1 = Date.now();
// пейлоад із функцією затримки — тільки на власному тестовому стенді
await request.get('/api/orders', { params: { id: "42' AND pg_sleep(3)--" } });
const probeMs = Date.now() - t1;
// не абсолютне число, а різниця з базовою відповіддю
expect(probeMs - baseMs).toBeGreaterThan(2000);
});
Що дивитися і чому:
- Оракул — це різниця, а не поріг.
probeMs > 3000бреше на повільній мережі;probeMs - baseMsвідсікає фонову латентність і лишає саме внесок . - Мовчазна сторінка помилки — привід перейти до сліпих технік, а не фінал. Якщо контентний варіант нічого не дав (сторінки для істини й хиби однакові), часовий працює навіть тоді, коли тіло байт у байт те саме.
- Один прогін нічого не доводить. Часову пробу повторюють і, за потреби, збільшують затримку — випадковий сплеск латентності не має відтворюватися на замовлення, а керована пауза має.
- Тільки свій стенд. Пейлоад із
pg_sleepнавантажує реальну базу; на чужому середовищі це вже не тест, а .
Кейс 3. NoSQL: у негативний набір кладуть структуру, а не рядок
Ендпоінт пошуку приймає JSON { "q": "..." }. Функціональні тести зелені, а дірку видно тільки тоді, коли перестати думати про поле як про рядок. У Mongo-подібному сховищі підміняють не значення, а тип: замість рядка кладуть обʼєкт з оператором — і структуру запиту фактично задає клієнт. Тому перевіряти треба тіло запиту цілком, а не значення полів: негативний набір містить саме підміну структури JSON.
import { test, expect } from '@playwright/test';
// Здоровий бекенд приймає лише рядок і відхиляє обʼєкт-оператор у полі.
// Керований клієнтом оператор не має доїжджати до сховища взагалі.
test('пошук відхиляє оператор у полі замість рядка', async ({ request }) => {
// базова лінія: звичайний рядковий запит
const ok = await request.post('/api/products/search', { data: { q: 'laptop' } });
expect(ok.status(), 'рядок — легітимний ввід').toBe(200);
// те саме поле, але замість рядка — обʼєкт з оператором
const injected = await request.post('/api/products/search', {
data: { q: { $where: 'this.price > 0' } },
});
// сервер має відхилити нерядкове поле, а не взяти оператор у запит
expect(injected.status(), 'оператор у полі не мусить прийматися').toBe(400);
});
Порівняння трьох варіантів того самого поля:
Що подаємо в q | Здоровий бекенд | Вразливий бекенд |
|---|---|---|
рядок "laptop" | 200, звичайна вибірка | 200, звичайна вибірка |
обʼєкт { "$regex": "..." } | відхилено: оператор від клієнта не приймається | запит збирається з обʼєкта, який прислав клієнт — структуру добору задає вже не бекенд |
обʼєкт { "$where": "..." } | відхилено: виконання коду на боці сервера вимкнене | виконання коду на боці бази або важке навантаження на CPU |
Що дивитися і чому:
- Індикатор може не бути у відповіді. Небезпечний
$whereне завжди міняє тіло відповіді; слід від нього — у логах бази або в стрибку навантаження на CPU, тож підозрілі команди моніторять окремо. - Тестуємо тіло, а не поле. UI-форма надішле рядок хоч що вводь; підміну структури видно лише на рівні API, тому цей набір живе в API-тестах, а не в браузерних.
- Захист — не «фільтрувати символи». Правильна відповідь бекенда — приймати обʼєкти запиту драйвера з контрольованим типом входу, а сирий фрагмент JSON від клієнта не виконувати як запит; тест лише фіксує, що ця межа тримається.
200без видимої зміни відповіді нічого не спростовує. Наслідків у дозволу надіслати$whereназвано рівно два — віддалене виконання коду й важке навантаження на CPU, — і жоден із них не зобовʼязаний зʼявитися в тілі відповіді.
Механізм і місце в мапі ризиків
- Можу пояснити через рух даних, а не через технологію: недовірений ввід доїжджає до інтерпретатора вклеєним у текст команди — і це один клас дефекту з різними мішенями (SQL, LDAP, XPath, команди ОС, аргументи програм), а не набір окремих багів.
- Знаю, що таке площина керування (control plane) і площина даних (data plane) — і чому мова запитів межі між ними сама не тримає.
- Не плутаю категорію й механізм: «інʼєкція» — назва категорії A05, «інʼєкційний дефект» — назва самого механізму; в LLM у цей список не входять.
- Памʼятаю позицію з роком: №1 у 2013 і 2017, №3 у 2021, №5 (A05) у 2025 — і що всередині категорії співіснують два профілі: XSS (частіша, вплив нижчий) і (рідша, вплив високий).
SQL-інʼєкція: класична і сліпа
- Можу назвати дві умови , і що потрібні обидві: непередбачені дані з недовіреного джерела і їхня участь у динамічній побудові запиту.
- Знаю наслідки без пом'якшень (читання й зміна даних, адміністративні операції над СУБД аж до зупинки, доступ до файлу на сервері бази) і можу пояснити обхід автентифікації: завжди істинна умова змушує запит повернути рядок, і застосунок пускає без пароля.
- Розрізняю три класи за каналом отримання даних — inband, out-of-band, inferential (сліпий) — і знаю, що сліпа відрізняється від звичайної рівно способом отримання даних, а різновидів у неї два: контентний і часовий.
- Можу пояснити, чому вердикт виносить — різниця з базовою відповіддю або , а не рядок помилки: загальна сторінка помилки дефекту не усуває, лише ховає індикатор, а часова техніка працює навіть тоді, коли вміст сторінки не змінюється взагалі (
pg_sleep(),WAIT FOR DELAY).
NoSQL, командна та LDAP-інʼєкція
- Можу означити через небезпечну побудову обʼєктів запиту, а не лише рядків, і знаю, що ризиків там більше, ніж у реляційних базах, а не «інші за складом».
- Знаю вектор, якого в SQL немає, — оператор від клієнта (
$where,$regex,$expr) і сирий фрагмент JSON, поданий як запит; памʼятаю два наслідки прикладу з$where: віддалене виконання коду й важке навантаження на CPU. - Розумію, чим відрізняється від інʼєкції коду (власного коду не треба, розширюється наявна функція, команда виконується з привілеями застосунку) і памʼятаю тезу, що знімає заперечення: кожна командна інʼєкція є водночас .
- Знаю порядок захисту для команд ОС: спершу взагалі не викликати їх (бібліотечні функції), далі два шари — структурне розділення плюс окрема валідація команди й аргументів.
- Можу пояснити, чому в LDAP «зроби як із SQL» не працює: безпечних параметризованих інтерфейсів запиту бракує, тож лишаються правильна функція кодування або фреймворк, а нормалізація йде перед валідацією.
Захист: параметризація і три інші варіанти
- Можу пояснити параметризацію як порядок дій: спершу визначено весь код запиту, значення передаються окремо через , і
tom' or '1'='1шукається як буквальне імʼя. - Знаю дві пастки, видимі лише в коді: параметризація має бути серверною (частина бібліотек склеює рядок у себе), а ідентифікатори — імена таблиці, стовпця, напрям сортування — плейсхолдером не передаються.
- Памʼятаю чотири варіанти OWASP по порядку (, безпечно реалізовані , і — з позначкою STRONGLY DISCOURAGED — екранування всього вводу) і чому «у нас збережені процедури» аргументом не є.
- Знаю межі решти варіантів: валідація за списком дозволеного повною не буває, випадає зовсім, щодо екранування шпаргалка OWASP і -89 дають протилежний пріоритет (стратегія проти механізму), а мінімізація привілеїв акаунта бази зменшує шкоду, а не сам дефект.
Тестування й межі автоматики
- Знаю, що починати треба з інвентаризації точок вводу: усі поля, що доїжджають у запит, включно з прихованими полями POST, а також заголовки, cookie, URL, JSON, SOAP і XML.
- Памʼятаю перші проби й чому саме вони (одинарна лапка як термінатор рядка, крапка з комою, роздільники коментарів
--і/* */,AND/OR, рядок замість числа), тримаю дисципліну «одне поле за раз» і знаю дві цілі тесту: знайти точки інʼєкції й оцінити досяжний рівень доступу. - Знаю межі автоматики: може не побачити викликів через власні обгортки й сторонні бібліотеки (хибнонегативні результати), а пасивний прохід лише читає трафік і вважається безпечним, тоді як активне сканування є справжньою — тільки свій стенд і тільки з дозволом.
Квіз
Перед стартом
- Питань: 18
- Поріг «зараховано»: ≥70% правильних відповідей.
- Результат впливає на прогрес; завалені питання підуть у чергу повторення.
- Квіз впливає на компліт теми: тема стає «пройдено», лише коли прочитано теорію І квіз складено на ≥70%.
Питання
Чому інʼєкція — це один клас дефекту, а не набір різних багів?