Senior: питання на співбесіді з теми «Безпека»
Питання з реальних співбесід з відповідями: Laravel і PHP, бази даних, JavaScript і фронтенд, Git, Docker, API, безпека й архітектура. Тими самими темами, що й тести.
4 питання
- Паролі - лише одностороннє хешування (Bcrypt/Argon2):
Hash::make()/Hash::check(). Ніколи не шифрування й не власні алгоритми. - PII (двостороннє) -
Crypt::encryptString()або кастencryptedна атрибуті моделі:protected $casts = ['ssn' => 'encrypted']; - Ключі та секрети - у
.env/ секретних сховищах (AWS Secrets Manager, Vault), не в git. РотаціяAPP_KEYпотребує перешифрування. - Транзит - лише HTTPS/TLS.
- Логи - маскувати PII; уникати
dd()у проді. - Доступ - принцип найменших привілеїв, audit log (наприклад,
spatie/laravel-activitylog).
CSP - HTTP-заголовок, що визначає, з яких джерел дозволено завантажувати ресурси (скрипти, стилі, зображення). Це потужний захист від XSS: навіть якщо зловмисник впровадить <script>, браузер не виконає його, якщо джерело не дозволене.
Content-Security-Policy: default-src 'self';
script-src 'self' https://cdn.example.com;
img-src 'self' data:;
У Laravel заголовок додають через middleware (вручну або пакетом на кшталт spatie/laravel-csp).
Практики:
- Уникати
'unsafe-inline'- використовувати nonce для інлайн-скриптів. - Спершу режим report-only (
Content-Security-Policy-Report-Only) зі збором звітів, щоб не зламати сайт.
За балансувальником чи CDN застосунок бачить з'єднання від проксі, а справжні дані клієнта приходять у заголовках X-Forwarded-For, X-Forwarded-Proto, X-Forwarded-Host.
Без налаштування:
$request->ip()повертає IP балансувальника - обмеження частоти й журнали «бачать» одного клієнта;$request->secure()-false, і Laravel генерує посилання зhttp://.
Довірені проксі:
->withMiddleware(function (Middleware $middleware): void {
$middleware->trustProxies(at: ['10.0.0.0/8']);
})
Laravel читає X-Forwarded-* лише від цих адрес. at: '*' безпечний, тільки коли застосунок недоступний напряму, - інакше будь-хто надішле X-Forwarded-For: 1.2.3.4 і обійде обмеження частоти чи журнали.
Довірені хости: абсолютні URL будуються з заголовка Host. Якщо вебсервер пропускає будь-який хост, запит на скидання пароля з підробленим Host дасть лист з посиланням на домен зловмисника - разом з токеном.
$middleware->trustHosts(at: ['^example\.com$'], subdomains: true);
Краще, коли вебсервер узагалі не приймає невідомі хости.
За Cloudflare реальний IP приходить ще й у CF-Connecting-IP; довіряти йому можна лише для запитів з діапазонів Cloudflare.
Перебір (/invoices/1, /invoices/2...) і скрапінг шукають дані, які віддаються без достатніх перевірок, або просто вивантажують усе відкрите.
Перша лінія - авторизація. Кожен запис перевіряється політикою, а запити списків починаються від власника. Якщо цього немає, решта заходів лише гальмує витік.
Не розкривати існування: для чужих ресурсів - 404, а не 403 (Response::denyAsNotFound()), щоб перебір не відрізняв «чуже» від «немає».
Обмеження частоти з розумом:
RateLimiter::for('lookups', function (Request $request) {
return Limit::perMinute(10)
->by($request->user()?->id ?: $request->ip())
->after(fn (Response $response) => $response->status() === 404);
});
after() рахує лише 404 - звичайні користувачі не впираються в ліміт, а перебір швидко зупиняється.
Непередбачувані ідентифікатори (UUID, ULID) у публічних URL ускладнюють перебір, але не замінюють авторизацію.
Проти масового збору відкритих даних:
- пагінація з обмеженням розміру сторінки, без «віддати все»;
- ліміти для гостей суворіші, ніж для автентифікованих;
- захист на рівні CDN (WAF, challenge) для явних ботів - він дешевший за обробку в PHP;
- моніторинг: різкий ріст 404 з одного джерела - сигнал.
Докладніше в документації: Обмеження частоти на основі відповіді