Security headers: HSTS, CSP, X-Frame-Options та інші
· 7 хв читання
Бекенд - фортеця, та друга половина захисту в браузері. HSTS, CSP та інші заголовки блокують XSS, clickjacking і MITM - і вони безкоштовні.
Чому вони важливі
Застосунок може бути ідеально захищеним на стороні backend і все одно залишатися вразливим до атак на стороні браузера: cross-site scripting (XSS), clickjacking, protocol downgrade, MIME confusion. Security-заголовки переносять захист у сам браузер.
Strict-Transport-Security (HSTS)
Примусово вмикає HTTPS для всіх майбутніх відвідувань. Після першого візиту через HTTPS браузер запам'ятовує домен і сам переписує будь-яке http://-посилання на https://, навіть якщо користувач клікне на хибне посилання.
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
max-age=63072000= діє 2 рокиincludeSubDomains= правило діє і для всіх піддоменів; воно вмикає HTTPS усюди, тож піддомен, що працює лише через HTTP, напр.staging.example.com, стане недоступним у браузеріpreload= дозволяє включення до списку HSTS preload, вбудованого в Chrome / Firefox / Safari
Увага:
Видалення HSTS з preload зі списку триває 6+ місяців. Не додавайте preload, доки не переконаєтеся, що HTTPS стабільно працює на всіх піддоменах.
Content-Security-Policy (CSP)
Найпотужніший, але водночас найскладніший у налаштуванні заголовок. Він задає whitelist того, звідки браузеру дозволено завантажувати скрипти, стилі, зображення та iframe-и. Без CSP атакувальник, здатний інжектувати <script> тег, може виконати будь-який JS; з CSP - лише код зі схвалених джерел.
Content-Security-Policy: default-src 'self'; script-src 'self' 'sha256-...'; img-src 'self' data: https://cdn.example.com; style-src 'self' 'unsafe-inline'; frame-ancestors 'none'
Поширені директиви:
default-src 'self'= за замовчуванням дозволяти лише ресурси зі свого доменуscript-src= JS-джерела (для inline-скриптів вкажіть hash або nonce)style-src= CSS-джерелаimg-src= зображенняconnect-src= AJAX, WebSocket, EventSourceframe-ancestors 'none'= ніхто не може вбудувати сторінку в iframe (краще, ніж X-Frame-Options)report-uri /csp-report= браузер надсилає JSON при кожному порушенні (ви ловите його в backend і логуєте)- Примітка:
report-uriсьогодні deprecated - браузери з підтримкоюreport-toйого ігнорують. Сучасний спосіб - директиваreport-toплюс окремий заголовокReporting-Endpoints; залиштеreport-uriлише як fallback для Firefox, який поки не підтримуєreport-to.
X-Frame-Options
Старіша альтернатива frame-ancestors. Захищає від clickjacking, коли атакувальник вставляє вашу сторінку як iframe і перекриває її невидимими кнопками.
X-Frame-Options: DENY
Значення: DENY (ніхто), SAMEORIGIN (лише мій домен), ALLOW-FROM uri (deprecated).
X-Content-Type-Options
X-Content-Type-Options: nosniff
Вимикає MIME sniffing, тож браузер поважає Content-Type, який повернув сервер. Без цього атакувальник може завантажити файл з неправильним типом (наприклад, зображення, яке насправді є HTML зі скриптом), і браузер може виконати його як вебсторінку.
Referrer-Policy
Referrer-Policy: strict-origin-when-cross-origin
Керує тим, скільки інформації про попередню сторінку браузер надсилає в заголовку Referer при кліку. Значення за замовчуванням у сучасних браузерах уже strict-origin-when-cross-origin, але явне встановлення заголовка гарантує узгоджену поведінку.
Permissions-Policy
Вимикає API, які вам не потрібні, такі як камера, мікрофон, GPS і геолокація. Атакувальник, що використовує XSS, не може запитати ці API.
Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=()
Практична конфігурація в nginx
server {
listen 443 ssl http2;
server_name example.com;
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always;
# preload тут навмисно пропущено - додавай його лише коли впевнений на 100% (див. пастку з preload вище)
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "DENY" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
# CSP розгалужена - визначте її відповідно до вашого застосунку
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; ..." always;
}
Ключове - always: без нього nginx пропускає заголовки при error response (4xx, 5xx).
Аудит поточного стану
Найпростіше через онлайн-інструмент. Наш header check покаже вам, які заголовки відсутні і які неправильні. Для ретельного аудиту securityheaders.com додатково дає оцінку A-F.
Висновок
Security-заголовки - одна з найкращих інвестицій у безпеку за співвідношенням зусиль і вигоди: зазвичай півгодини налаштування в reverse proxy проти цілої категорії атак на стороні браузера. Аудит раз на півроку в межах регулярного обслуговування - розумний мінімум.
Безкоштовний аудит security headers
Без реєстрації, результат за три секунди.
Спробуйте ePulz.io безкоштовно - 7 днів без банківської картки.
Створити обліковий запис