Олексій Синяєв
Найняти
Навігація сторінкою статті
Статті 6 хв читання

Чому безпека важлива у веб-розробці

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

Зміст

Коротко

  • Ви не побудуєте щось незламне. Мета — стиснути експлуатовану поверхню й обмежити радіус ураження, коли щось усе ж прорветься.
  • Жменька проблем спричиняє більшість реальних зломів: зламаний контроль доступу, ін’єкції через код, що обходить фреймворк, витеклі секрети та застарілі залежності.
  • Фреймворки блокують більшість ін’єкцій безкоштовно — поки ви не потягнетеся за сирим SQL чи неекранованим виводом. Небезпека — у коді, що сходить із безпечного шляху.
  • Авторизуйте кожну дію на сервері. Сховати кнопку — це не контроль доступу; атакувальник кличе ендпоінт напряму.

Найгірший інцидент безпеки, який мені довелося допомагати розгрібати, був не хитрим експлойтом. Це був пароль бази даних у закоміченому .env-файлі в репозиторії, який хтось вважав приватним. Жодного zero-day, жодного вмілого атакувальника — просто облікові дані, яких ніколи не мало бути в git, знайдені й використані. Так виглядає більшість реальних зломів: не кіношний хакінг, а нудний, відворотний пробіл, за який ніхто не відповідав.

«Безпека важлива» — це не порада. Ось версія, яку я б реально дав PHP-, Laravel- чи WordPress-розробнику: коротка модель загроз і конкретні пробіли, через які компрометують сайти, приблизно в тому порядку, в якому вони й трапляються.

Думайте в термінах поверхні та радіуса ураження

Ідеальна безпека — не мета, бо її не існує. Два питання дають вам більшу частину користі. Перше: яка експлуатована поверхня — кожне місце, де недовірений ввід досягає вашого коду, кожні облікові дані, кожна залежність, яку ви не писали? Друге: коли одне з цього падає, як далеко розходиться шкода? Витеклий read-only API-ключ — поганий день; витеклий root-пароль бази — катастрофа. Більшість хороших рішень з безпеки приходять зі стиснення першого і стримування другого, а не з гонитви за ідеальною оцінкою.

Зламаний контроль доступу: тихий номер один

Найчастіший серйозний ґандж — він же найменш драматичний: код, що перевіряє, чи залогінені ви, але не те, до чого вам дозволено торкатися. Класична форма — ендпоінт, що довіряє ID із запиту:

Code
// Anyone logged in can read anyone's invoice
public function show($id)
{
    return Invoice::findOrFail($id);
}

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

Code
public function show(Invoice $invoice)
{
    $this->authorize('view', $invoice); // policy checks ownership
    return $invoice;
}

Сховати UI — це не контроль доступу

Якщо єдине, що зупиняє користувача від дії, — це що кнопка не відрендерена, контролю немає взагалі. Кожен ендпоінт має перевіряти, що поточному користувачу дозволено діяти з конкретним ресурсом — на стороні сервера, щоразу.

Ін’єкції: фреймворки захищають, поки ви не відмовитеся

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

Code
// Vulnerable: input concatenated into SQL
DB::select("SELECT * FROM users WHERE email = '$email'");

// Safe: parameter binding
DB::select('SELECT * FROM users WHERE email = ?', [$email]);

XSS — та сама історія на виводі. {{ }} у Blade екранує автоматично; небезпека — {!! !!}, що друкує сирий HTML. У WordPress це вивід користувацьких даних без esc_html() чи esc_attr(). Правило, що запобігає більшій частині: ніколи не довіряйте вводу на вході, завжди екрануйте на виході й ставтеся до кожного {!! !!} чи неекранованого echo як до місця, що потребує обґрунтування.

Секрети та залежності: нудні зломи

Два пробіли, що стоять за великою часткою реальних компрометацій, не мають нічого спільного з логікою застосунку. Перший — витеклі секрети: облікові дані в закоміченому .env, API-ключ, вставлений у репозиторій чи чат. Тримайте секрети поза контролем версій, а якщо один витік — ротуйте негайно й вважайте його повністю скомпрометованим; приватний репозиторій — небезпечне місце для живих облікових даних. Я писав рівно про цей сценарій відмови у статті про випадково запушені секрети в git.

Другий — застарілі залежності, а для WordPress зокрема плагіни — найбільший одиничний вектор злому. Відома вразливість у непропатченому плагіні — це опублікований, скриптований експлойт. Ставтеся до оновлень як до роботи з безпеки, а не рутини: запускайте composer audit, тримайте плагіни актуальними й видаляйте ті, що не використовуєте. На Bedrock-подібній установці блокування змін файлів із браузера в продакшені (DISALLOW_FILE_MODS) тримає набір плагінів під контролем версій, де його можна аудити.

Не довіряйте жодному payload ззовні

Будь-який запит від зовнішньої системи недовірений, доки не доведено протилежне, включно з вебхуками. Платіжний чи інтеграційний вебхук, на який ви реагуєте без перевірки підпису, — це відкритий ендпоінт, куди будь-хто може слати підроблені події. Перевіряйте підпис до того, як щось робити з тілом — ту саму думку я проводжу про Stripe в гайді з Laravel Cashier. Це стає драматично простіше, коли зовнішні інтеграції живуть за однією межею, яку можна аудити, а не розкидані по контролерах — структурний аргумент у статті про впровадження та інверсію залежностей.

Заголовки й транспорт: реально, але ешелонований захист

HTTPS усюди, HSTS і content security policy варто мати — це значущий шар, і CSP зокрема обмежує шкоду від XSS, що проковзнув. Але це ешелонований захист, а не головна подія. Суворий CSP не врятує ендпоінт зі зламаним контролем доступу. Поставте заголовки, а потім витрачайте увагу на авторизацію, ін’єкції, секрети й залежності — там, де зломи й трапляються.

Помилки, що ведуть до реальних зломів

Авторизація лише в UI

Сховати елемент — це не перевірка. Перевіряйте права на стороні сервера на кожному ендпоінті відносно конкретного ресурсу.

Сирий SQL з інтерпольованим вводом

Конкатенація даних запиту в SQL знову відкриває ін’єкцію, яку фреймворк закрив. Використовуйте біндинги або query builder.

Неекранований вивід

{!! !!} у Blade або неекранований echo у WordPress друкує сирий користувацький ввід. Екрануйте на виводі за замовчуванням.

Секрети в репозиторії

Закомічені облікові дані скомпрометовані, приватний репозиторій чи ні. Тримайте секрети поза git і ротуйте будь-які, що витекли.

Застарілі плагіни й пакети

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

Довіра до payload вебхуків

Неперевірений ендпоінт вебхука приймає підроблені події. Перевіряйте підпис до дій із тілом.

Безпека — це ще й процес

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

FAQ

Яка найчастіша вразливість вебзастосунків?
Зламаний контроль доступу — ендпоінти, що підтверджують, що користувач автентифікований, але не те, що йому авторизовано діяти з конкретним ресурсом. Зміна ID у запиті для читання чужих даних — класичний випадок. Авторизацію треба забезпечувати на стороні сервера на кожній дії.
Чи робить використання Laravel або WordPress сайт безпечним за замовчуванням?
Вони запобігають багато чому — Eloquent параметризує SQL, Blade екранує вивід — але лише поки ви на безпечному шляху. Сирі запити з інтерпольованим вводом, неекранований {!! !!}, витеклі секрети й застарілі плагіни обходять ці захисти. Фреймворк знижує ризик; він не знімає вашу відповідальність.
Що робити, якщо я випадково закомітив секрет у git?
Вважайте його повністю скомпрометованим і ротуйте негайно — змініть пароль або відкличте ключ, навіть якщо репозиторій приватний. Видалення файлу в пізнішому коміті не допомагає, бо значення лишається в історії git і могло бути вже скопійоване.
Чи достатньо заголовків безпеки на кшталт CSP, щоб захистити сайт?
Ні. Заголовки на кшталт HSTS і content security policy — цінний ешелонований захист і обмежують шкоду від деяких атак, але вони не лагодять зламаний контроль доступу, ін’єкції чи витеклі облікові дані. Використовуйте їх на додаток до серверної авторизації й безпечної обробки вводу, а не замість них.

Схожі статті

Оновлено:

Поділитися статтею

LinkedIn X Email

Зв'язатися

Працюєте над схожою задачею? Давайте обговоримо.

Відкритий до розмови про архітектуру, Laravel, WordPress, продуктивність і практичні інженерні задачі.

Зв'язатися Переглянути кейси

Дивіться також

Статті

Як зрозуміти, що AI-агент втратив контекст: state-canary в AGENTS.md і CLAUDE.md

State-canary — простий observability-патерн для AI coding agents: один рядок стану в кожній відповіді…
Статті

Частина 3. Місяць з AI-щоденником: як шукати зв’язки між сном, стресом і тренуваннями

Як аналізувати AI-щоденник після першого місяця: виправлення розпізнавання, чесна рефлексія з джерелами, Obsidian, вартість…
Статті

Частина 2. Hermes Agent + DeepSeek на Ubuntu: повний мануал AI-щоденника в Telegram

Покроковий мануал: Hermes Agent і DeepSeek на Ubuntu, закритий Telegram-бот, локальний faster-whisper, Markdown vault,…