Назад до блогу

Security headers: HSTS, CSP, X-Frame-Options та інші

· 7 хв читання

Бекенд - фортеця, та друга половина захисту в браузері. HSTS, CSP та інші заголовки блокують XSS, clickjacking і MITM - і вони безкоштовні.

Security headers: HSTS, CSP, X-Frame-Options та інші

Чому вони важливі

Застосунок може бути ідеально захищеним на стороні 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, EventSource
  • frame-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 днів без банківської картки.

Створити обліковий запис