Kravchenko

Web Lab

АудитБлогКонтакты

Kravchenko

Web Lab

Разрабатываем сайты и автоматизацию на современных фреймворках под ключ

Услуги
ЛендингМногостраничныйВизитка
E-commerceБронированиеПортфолио
Навигация
БлогКонтактыАудит
Обратная связь
+7 921 567-11-16
info@kravlab.ru
с 09:00 до 18:00

© 2026 Все права защищены

•

ИП Кравченко Никита Владимирович

•

ОГРНИП: 324784700339743

Политика конфиденциальности

HTTP‑заголовки безопасности (CSP, HSTS, Permissions‑Policy): как защитить сайт от XSS и сэкономить на инцидентах

Разработка и технологии10 декабря 2025 г.
Правильно настроенные заголовки безопасности снижают риск XSS, кражи данных и внедрения вредоносных скриптов. Разбираем, какие заголовки нужны в 2025 году, как внедрить их без падений продаж и как измерить эффект для бизнеса.
HTTP‑заголовки безопасности (CSP, HSTS, Permissions‑Policy): как защитить сайт от XSS и сэкономить на инцидентах

• Оглавление

  • Зачем бизнесу заголовки безопасности
  • Какие заголовки нужны в 2025 и зачем они
  • Пошаговый план внедрения без поломок
  • Примеры конфигурации: Nginx, Django, Node/Express
  • CSP с nonce: безопасные скрипты без 'unsafe-inline'
  • Тестирование и мониторинг
  • Типичные ошибки и как их избежать
  • Кейсы и оценка эффекта для бизнеса
  • Чек‑лист для быстрого старта

Зачем бизнесу заголовки безопасности

Атаки на веб‑приложения чаще происходят не из‑за «хакинга из фильмов», а из‑за мелочей: неконтролируемых скриптов, встраивания страниц в чужие сайты, утечек реферера, неверно настроенных ответов сервера. Правильные HTTP‑заголовки безопасности создают «пояс безопасности» поверх кода и инфраструктуры.

Что получает бизнес:

  • Меньше инцидентов: CSP блокирует XSS и внедрение сторонних скриптов, HSTS исключает откат на незащищённый HTTP.
  • Защита кассы и формы оплаты: запрет на встраивание в чужие фреймы и строгая политика источников.
  • Соответствие требованиям аудиторов и корпоративных политик: многие проверки сразу закрываются корректной конфигурацией заголовков.
  • Экономия: меньше затрат на расследование, реагирование и репутационные риски.

Какие заголовки нужны в 2025 и зачем они

  • Content-Security-Policy (CSP): задаёт «белый список» источников для скриптов, стилей, изображений и т. д., блокирует внедрение опасного кода.
  • Strict-Transport-Security (HSTS): обязывает браузер использовать только HTTPS; с опцией preload — даже при первой загрузке.
  • X-Content-Type-Options: nosniff. Запрещает «угадывание» типа содержимого, закрывает ряд векторов XSS.
  • Referrer-Policy: управляет тем, какие данные запроса передаются на внешние сайты. Рекомендуется strict-origin-when-cross-origin.
  • Permissions-Policy: ограничивает доступ к камере, микрофону, гео и др. по умолчанию. Полезно для приватности и снижения поверхности атак.
  • X-Frame-Options или frame-ancestors в CSP: защита от clickjacking (встраивание вашей страницы в чужой сайт). Современный способ — директива frame-ancestors в CSP.
  • Cross-Origin-Opener-Policy (COOP) и Cross-Origin-Embedder-Policy (COEP): повышают изоляцию контента. Включайте осмотрительно: могут сломать интеграции, но полезны для жёстких режимов и WebAssembly/SharedArrayBuffer.

Пошаговый план внедрения без поломок

  1. Инвентаризация источников
  • Соберите список доменов, откуда реально грузятся скрипты/стили/шрифты/изображения (ваш домен, CDN, аналитика). Инструменты: DevTools → Network, отчёты CDN, сбор логов.
  1. Старт с отчётным режимом CSP
  • Включите Content-Security-Policy-Report-Only и собирайте отчёты о нарушениях. Это не блокирует, но показывает, что сломается при боевом включении.
  1. Минимизируйте «дырки»
  • Уберите 'unsafe-inline' и 'unsafe-eval', замените inline‑скрипты на внешние файлы или используйте nonce/хеши.
  • Для аналитики и виджетов явно перечислите источники или подключайте через ваш домен/CDN.
  1. Переключение в боевой режим
  • После 1–2 недель отчётов и исправлений включите рабочий CSP. Оставьте Report-Only параллельно, чтобы ловить новые нарушения.
  1. HSTS с постепенным ужесточением
  • Сначала max-age на 1–7 дней. Если всё ок — увеличьте до 6–12 месяцев, потом включите preload (после проверки субдоменов и редиректов на 443).
  1. Мониторинг
  • Включите метрики: количество нарушений CSP, скорость загрузки (чтобы исключить влияние на производительность), конверсию. Заводите алерты на всплески нарушений.

Примеры конфигурации: Nginx, Django, Node/Express

Nginx: базовый набор заголовков

server {
    listen 443 ssl http2;
    server_name example.com;

    # HSTS: вначале поставьте меньший max-age и только потом увеличьте и включите preload
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;

    # Базовые заголовки безопасности
    add_header X-Content-Type-Options "nosniff" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;
    add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;

    # CSP — пример для сайта с локальными скриптами и CDN шрифтами
    # Начните с Report-Only, затем переключайте на Content-Security-Policy
    add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' fonts.googleapis.com; font-src 'self' fonts.gstatic.com; img-src 'self' data:; frame-ancestors 'none'; base-uri 'self'; form-action 'self'" always;

    # Если хотите собирать отчёты о нарушениях CSP (совместите с Report-Only):
    # add_header Content-Security-Policy-Report-Only "default-src 'self'; report-uri /csp-report" always;

    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    location /csp-report {
        proxy_pass http://127.0.0.1:8000/csp-report;
    }
}

Django: безопасные настройки без «инлайна»

# settings.py

SECURE_SSL_REDIRECT = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
SECURE_HSTS_SECONDS = 31536000  # включайте постепенно
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True
SECURE_REFERRER_POLICY = "strict-origin-when-cross-origin"
SECURE_CONTENT_TYPE_NOSNIFF = True

MIDDLEWARE = [
    "django.middleware.security.SecurityMiddleware",
    # другие middleware
]

# Вариант CSP через django-csp (pip install django-csp)
INSTALLED_APPS = [
    # ...
    "csp",
]
MIDDLEWARE += ["csp.middleware.CSPMiddleware"]

CSP_DEFAULT_SRC = ("'self'",)
CSP_SCRIPT_SRC = ("'self'",)  # без инлайна — скрипты из статических файлов
CSP_STYLE_SRC = ("'self'", "fonts.googleapis.com")
CSP_FONT_SRC = ("'self'", "fonts.gstatic.com")
CSP_IMG_SRC = ("'self'", "data:")
CSP_FRAME_ANCESTORS = ("'none'",)
CSP_BASE_URI = ("'self'",)
CSP_FORM_ACTION = ("'self'",)

# Чтобы перейти на nonce: используйте {% csp_nonce %} в шаблонах и внешний или инлайновый скрипт с nonce
# Пример шаблона:
# <script nonce="{{ request.csp_nonce }}">console.log('ok');</script>

Если вам нужен гибкий контроль над заголовками без пакета, можно выставлять их на уровень реверс‑прокси (Nginx) или через собственный middleware в Django — но удобнее и надёжнее использовать готовый django-csp.

Node.js/Express: Helmet + CSP с отчётами

// app.js
const express = require('express');
const crypto = require('crypto');
const helmet = require('helmet');

const app = express();
app.enable('trust proxy');

// Генерация nonce на каждый запрос
app.use((req, res, next) => {
  res.locals.nonce = crypto.randomBytes(16).toString('base64');
  next();
});

// Базовые заголовки
app.use(helmet({
  referrerPolicy: { policy: 'strict-origin-when-cross-origin' },
  xContentTypeOptions: true,
  frameguard: false, // будем использовать frame-ancestors в CSP
  contentSecurityPolicy: false // зададим отдельно, чтобы добавить nonce
}));

// HSTS — включайте только за HTTPS и после тестирования субдоменов
app.use(helmet.hsts({ maxAge: 31536000, includeSubDomains: true, preload: true }));

// CSP с nonce и отчётами
app.use((req, res, next) => {
  const nonce = res.locals.nonce;
  const csp = [
    "default-src 'self'",
    `script-src 'self' 'nonce-${nonce}' 'strict-dynamic'`,
    "style-src 'self' fonts.googleapis.com",
    "font-src 'self' fonts.gstatic.com",
    "img-src 'self' data:",
    "frame-ancestors 'none'",
    "base-uri 'self'",
    "form-action 'self'",
    // Отчёты о нарушениях (совместимость):
    "report-uri /csp-report"
  ].join('; ');

  res.setHeader('Content-Security-Policy', csp);
  next();
});

app.use(express.json({ type: ['application/json', 'application/csp-report', 'application/reports+json'] }));

app.post('/csp-report', (req, res) => {
  // Логику можно отправлять в SIEM/лог-хранилище
  console.warn('CSP violation:', JSON.stringify(req.body));
  res.status(204).end();
});

app.get('/', (req, res) => {
  const nonce = res.locals.nonce;
  res.send(`<!doctype html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Secure App</title>
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600&display=swap" rel="stylesheet">
  </head>
  <body>
    <h1>Здравствуйте!</h1>
    <script nonce="${nonce}">console.log('CSP nonce ok');</script>
  </body>
</html>`);
});

app.listen(3000, () => console.log('Server on http://localhost:3000'));

CSP с nonce: безопасные скрипты без 'unsafe-inline'

Задача nonce — разрешить конкретный инлайновый скрипт и запретить остальные. Браузер сравнивает значение атрибута nonce у тега

Ключевые правила:

  • Генерируйте nonce на каждый запрос случайно (16+ байт), не переиспользуйте.
  • Не передавайте nonce в URL или внешним доменам.
  • Для динамически добавляемых скриптов используйте 'strict-dynamic': тогда браузер доверит скриптам, которые загружены теми, у кого есть nonce.

Альтернатива — хеши (sha256-...): подходят для статического инлайна, но неудобны при частых изменениях.

Тестирование и мониторинг

  • Быстрая проверка заголовков:
curl -I https://example.com | sed -n '/Strict-Transport-Security\|Content-Security-Policy\|Referrer-Policy\|Permissions-Policy\|X-Content-Type-Options/p'
  • Браузерные инструменты: Chrome DevTools → Security/Network, вкладка Issues показывает нарушения CSP.
  • Сервисы проверки заголовков: Mozilla Observatory, securityheaders.com, Lighthouse.
  • Отчёты CSP: собирайте на отдельную конечную точку, сохраняйте в лог‑хранилище и ставьте алерты на всплески.

Метрики для бизнеса:

  • Доли страниц с валидным CSP/HSTS.
  • Количество заблокированных попыток XSS (по отчётам) и тренд после релизов.
  • Время реакции на инциденты до/после внедрения.
  • Влияние на конверсию (не должно просесть — на тестовом трафике проверяйте особенно формы и оплату).

Типичные ошибки и как их избежать

  • 'unsafe-inline' и 'unsafe-eval': удобно, но открывает XSS. Используйте nonce или внешние файлы.
  • Слишком широкий список источников: *.cdn.com без нужды — приглашение для злоумышленника. Ограничивайте конкретными доменами и протоколами.
  • Забыли про frame-ancestors: без него возможны атаки через встраивание (clickjacking). Добавьте 'none' или конкретные доверенные домены.
  • Ранний preload для HSTS: если не все субдомены отдают HTTPS — пользователи начнут получать ошибки. Внедряйте поэтапно.
  • COOP/COEP без анализа: может сломать интеграции с внешними сайтами, окнами авторизации. Включайте адресно и тестируйте.
  • Проксирующие слои стирают заголовки: удостоверьтесь, что CDN/балансировщик их не убирает и не затирает.
  • Инлайновые события в HTML (onclick и т. п.): перепишите на addEventListener или используйте nonce.

Кейсы и оценка эффекта для бизнеса

Пример: интернет‑ритейл с 500 тыс. визитов/сутки.

  • До: периодические всплески подозрительных скриптов через сторонние виджеты, единичные инциденты с переадресацией клиентов на фишинг, 2–3 расследования в квартал (каждое — 20–40 часов работы команды).
  • После: включён CSP с nonce, ужесточены источники (analytic.example.com через собственный домен), frame-ancestors 'none', HSTS 12 месяцев + preload. Итог — за 2 квартала 0 инцидентов, 30–60 часов работы команды в квартал высвобождено. На A/B тесте конверсия не изменилась, скорость загрузки — без деградации.

Где экономия:

  • Снижение затрат на реагирование и простои.
  • Меньше негативных упоминаний и обращений в поддержку.
  • Быстрое прохождение внешних аудитов (меньше итераций и доработок).

Чек‑лист для быстрого старта

  • Перечислить реальные источники ресурсов (скрипты, стили, шрифты, изображения).
  • Включить CSP в режиме Report-Only и собирать отчёты 1–2 недели.
  • Убрать 'unsafe-inline'/'unsafe-eval': перевести инлайн‑скрипты в файлы или использовать nonce/хеши.
  • Настроить HSTS (с малого max-age → 12 месяцев → preload).
  • Выставить Referrer-Policy, X-Content-Type-Options, Permissions-Policy, frame-ancestors.
  • Проверить, что CDN/балансировщик сохраняет заголовки.
  • Включить мониторинг нарушений CSP и алерты.
  • Зафиксировать метрики: доля страниц с заголовками, количество нарушений, влияние на конверсию.

Итог: корректно настроенные заголовки безопасности — это быстрая и недорогая мера, которая даёт ощутимую защиту и помогает экономить на инцидентах, не мешая развитию продукта.


безопасностьCSPDevSecOps