Коротко
- Ви не побудуєте щось незламне. Мета — стиснути експлуатовану поверхню й обмежити радіус ураження, коли щось усе ж прорветься.
- Жменька проблем спричиняє більшість реальних зломів: зламаний контроль доступу, ін’єкції через код, що обходить фреймворк, витеклі секрети та застарілі залежності.
- Фреймворки блокують більшість ін’єкцій безкоштовно — поки ви не потягнетеся за сирим SQL чи неекранованим виводом. Небезпека — у коді, що сходить із безпечного шляху.
- Авторизуйте кожну дію на сервері. Сховати кнопку — це не контроль доступу; атакувальник кличе ендпоінт напряму.
Найгірший інцидент безпеки, який мені довелося допомагати розгрібати, був не хитрим експлойтом. Це був пароль бази даних у закоміченому .env-файлі в репозиторії, який хтось вважав приватним. Жодного zero-day, жодного вмілого атакувальника — просто облікові дані, яких ніколи не мало бути в git, знайдені й використані. Так виглядає більшість реальних зломів: не кіношний хакінг, а нудний, відворотний пробіл, за який ніхто не відповідав.
«Безпека важлива» — це не порада. Ось версія, яку я б реально дав PHP-, Laravel- чи WordPress-розробнику: коротка модель загроз і конкретні пробіли, через які компрометують сайти, приблизно в тому порядку, в якому вони й трапляються.
Думайте в термінах поверхні та радіуса ураження
Ідеальна безпека — не мета, бо її не існує. Два питання дають вам більшу частину користі. Перше: яка експлуатована поверхня — кожне місце, де недовірений ввід досягає вашого коду, кожні облікові дані, кожна залежність, яку ви не писали? Друге: коли одне з цього падає, як далеко розходиться шкода? Витеклий read-only API-ключ — поганий день; витеклий root-пароль бази — катастрофа. Більшість хороших рішень з безпеки приходять зі стиснення першого і стримування другого, а не з гонитви за ідеальною оцінкою.
Зламаний контроль доступу: тихий номер один
Найчастіший серйозний ґандж — він же найменш драматичний: код, що перевіряє, чи залогінені ви, але не те, до чого вам дозволено торкатися. Класична форма — ендпоінт, що довіряє ID із запиту:
// Anyone logged in can read anyone's invoice
public function show($id)
{
return Invoice::findOrFail($id);
}Поміняйте ID в URL — і ви читаєте чужі дані. Сховати посилання в UI не змінює нічого, бо атакувальник кличе ендпоінт напряму. Авторизація має відбуватися на сервері, для кожної дії, відносно поточного користувача:
public function show(Invoice $invoice)
{
$this->authorize('view', $invoice); // policy checks ownership
return $invoice;
}Сховати UI — це не контроль доступу
Якщо єдине, що зупиняє користувача від дії, — це що кнопка не відрендерена, контролю немає взагалі. Кожен ендпоінт має перевіряти, що поточному користувачу дозволено діяти з конкретним ресурсом — на стороні сервера, щоразу.
Ін’єкції: фреймворки захищають, поки ви не відмовитеся
SQL-ін’єкції та міжсайтовий скриптинг старі, і сучасні фреймворки блокують їх за замовчуванням — саме тому решта випадків приходить із коду, що сходить із безпечного шляху. Eloquent і біндинги параметризують SQL за вас; вразливість з’являється, коли хтось конкатенує ввід у сирий запит:
// 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 — цінний ешелонований захист і обмежують шкоду від деяких атак, але вони не лагодять зламаний контроль доступу, ін’єкції чи витеклі облікові дані. Використовуйте їх на додаток до серверної авторизації й безпечної обробки вводу, а не замість них.
Схожі статті
- Випадково запушили секрети в git — розбирає сценарій витоку облікових даних і як із нього відновитися.
- Laravel Cashier і Stripe — про перевірку підписів вебхуків, щоб зовнішні payload не можна було підробити.




