Перейти к содержанию
HexaTransfer
Вернуться к блогу
Шифрование и безопасность

Заголовки безопасности для веб-приложений: полное руководство по настройке

Настройте необходимые заголовки безопасности для приложения передачи файлов. CSP, HSTS, X-Frame-Options против распространённых веб-атак.

Заголовки безопасности — это поля HTTP-ответа, определяющие ограничения поведения страницы в браузере. Для приложения передачи файлов с клиентским шифрованием AES-256-GCM особую роль играют шесть заголовков: Strict-Transport-Security — для принудительного использования HTTPS, Content-Security-Policy — для блокировки инъекций скриптов, X-Frame-Options — для защиты от кликджекинга, Referrer-Policy — для предотвращения утечек фрагментов URL, Permissions-Policy — для отключения неиспользуемых API браузера, и Cross-Origin-Opener-Policy — для изоляции контекста просмотра. Правильная настройка этих заголовков блокирует 80% практических клиентских атак без единой строки изменений в JavaScript.

HSTS и список предзагрузки

Strict-Transport-Security: max-age=63072000; includeSubDomains; preload сообщает браузерам никогда не подключаться по обычному HTTP в течение двух лет. Директива preload делает вас кандидатом для включения в список предзагрузки HSTS Chrome (hstspreload.org), поставляемый вместе с браузером — даже первый запрос к вашему домену пойдёт по HTTPS, устраняя начальное окно уязвимости MITM. Включение в список необратимо; удаление занимает месяцы. Сначала протестируйте с max-age=300 несколько дней. Сервис передачи файлов без предзагрузки HSTS находится в одном DNS-перехвате от подмены формы загрузки.

Content Security Policy, работающий на практике

CSP — самый сложный в развёртывании и наиболее ценный заголовок. Строгая политика для приложения передачи файлов выглядит так: default-src 'none'; script-src 'self' 'wasm-unsafe-eval'; connect-src 'self' https://upload.hexatransfer.com; style-src 'self'; img-src 'self' data:; font-src 'self'; frame-ancestors 'none'; base-uri 'none'; form-action 'self'. Никаких встроенных скриптов, никакого eval кроме wasm, никаких сторонних подключений. Перенесите любые встроенные обработчики событий в addEventListener во внешних файлах. 'wasm-unsafe-eval' необходим для libsodium.js — без него Argon2id не инициализируется.

Subresource Integrity для каждого бандла

Если ваш JavaScript загружается с CDN типа jsDelivr или unpkg, добавьте атрибуты integrity="sha384-..." к каждому тегу script. Браузер откажет в выполнении скриптов, чей хэш не совпадает — взломанный CDN не сможет незаметно подменить бандл. Для самостоятельно размещённых скриптов на вашем домене SRI менее критичен, но всё равно полезен. Сочетайте SRI с require-sri-for script style в CSP или контролируйте через конвейер сборки. HexaTransfer публикует хэши для каждого релиза, чтобы параноидальные пользователи могли проверить их вручную.

X-Frame-Options и frame-ancestors

Атаки кликджекинга загружают вашу страницу загрузки в прозрачный iframe поверх другой страницы, заставляя пользователей нажимать «отправить» для файла, которым они не намеревались делиться. X-Frame-Options: DENY блокирует любое встраивание во фрейм; современная замена — Content-Security-Policy: frame-ancestors 'none'. Используйте оба — старые браузеры поддерживают только устаревший заголовок, новые предпочитают CSP. Никогда не применяйте SAMEORIGIN для приложения передачи файлов: у вас нет законных причин встраивать интерфейс загрузки с другой страницы.

Referrer-Policy для предотвращения утечек фрагментов

Браузеры по умолчанию исключают фрагменты URL (часть #key=..., где хранится ключ дешифрования) из заголовков Referer, однако путь URL всё равно утекает. Referrer-Policy: no-referrer блокирует всю реферерную информацию — никакого заголовка Referer на исходящих ссылках, никаких межсайтовых утечек, никакой внешней трекерной идентификации по URL. Для страницы скачивания вида /d/7Kj9xQmN2vP8rBwLsE4fT#k=abc это предотвращает утечку слага на внешние домены при переходах. Устанавливайте заголовок на уровне всего сайта — не полагайтесь на атрибут rel="noreferrer" для каждой ссылки.

Permissions-Policy для глубокой защиты

Если ваше приложение не использует камеру, микрофон, геолокацию или USB API, явно запретите их: Permissions-Policy: camera=(), microphone=(), geolocation=(), usb=(), bluetooth=(), accelerometer=(), magnetometer=(), gyroscope=(), payment=(). XSS, прошедший мимо CSP, всё равно не сможет включить веб-камеру для записи лица пользователя. Этот заголовок дёшев в развёртывании, не влияет на UX рабочего процесса передачи файлов и сигнализирует проверяющим безопасность, что вы продумали изоляцию.

Заголовки Cross-Origin-изоляции

Для доступа к высокоточным таймерам и SharedArrayBuffer (необходимым некоторым реализациям wasm-криптографии) браузеры требуют кросс-сайтовой изоляции через Cross-Origin-Opener-Policy: same-origin и Cross-Origin-Embedder-Policy: require-corp. Эти заголовки также защищают от Spectre-подобных атак по сторонним каналам, способных похитить ключи AES из соседних источников. Компромисс: встроенные сторонние ресурсы (видео YouTube, Stripe Checkout) перестанут работать, если не передают Cross-Origin-Resource-Policy: cross-origin. Для узкоспециализированного сервиса передачи файлов без сторонних встроек изоляция достаётся бесплатно.

Cache-Control для чувствительных страниц

Страница подтверждения скачивания может отображать краткосрочный ключ дешифрования или токен сессии. Предотвратите кэширование: Cache-Control: no-store, must-revalidate и Pragma: no-cache. Не ограничивайтесь только no-cache — он допускает повторную валидацию у источника, а значит, кэширование всё равно происходит. Для JavaScript-бандла страницы загрузки применяется обратная логика: длинный max-age с именами файлов, содержащими хэш контента (/js/main-a7b3c9.js), чтобы CDN-кэширование работало без проблем с инвалидацией. Применяйте заголовки точечно, в зависимости от пути.

X-Content-Type-Options и перехват MIME

X-Content-Type-Options: nosniff запрещает браузерам угадывать MIME-типы по содержимому. Без него файл .txt, загруженный злоумышленником с тегами <script>, может быть отрендерен как HTML при обратной отдаче. Для сервиса передачи, который отдаёт файлы, загруженные пользователями, сочетайте nosniff с Content-Disposition: attachment; filename="...", чтобы браузер загружал, а не отображал файл. Проверяйте имена файлов на попытки path traversal (../../../etc/passwd) на стороне сервера — не доверяйте метаданным загрузки ни для чего, кроме отображения.

Мониторинг и отчёты CSP

Сначала разверните CSP в режиме report-only, собирайте нарушения на конечную точку report-uri в течение недели, исправляйте легитимные проблемы, затем переходите к принудительному применению. Используйте Content-Security-Policy-Report-Only для наблюдения, переключитесь на Content-Security-Policy для применения политики. Конечная точка отчётов получает JSON POST с описанием каждого нарушения: заблокированный URI, нарушенная директива, исходный файл, номер строки. Такие сервисы, как Report URI или самостоятельно развёрнутый Sentry, собирают эти данные. Проверяйте еженедельно — реальные атаки проявляются как нетипичные заблокированные URI, которых вы раньше не встречали.

Оцените свою работу

Запустите URL продакшена через securityheaders.com и Mozilla Observatory. Оценка A или A+ — не совершенство, но базовый стандарт. Большинство конкурентов в сфере передачи файлов получают B или ниже, потому что забывают о Permissions-Policy или допускают 'unsafe-inline' в CSP. Небольшой сервис легко обходит WeTransfer по оценке заголовков безопасности — заголовки ничего не стоят в добавлении, а разговор с аудиторами SOC 2 о причинах нестрогого CSP становится намного короче, если вы изначально придерживались строгих правил.

Попробуйте на hexatransfer.com — бесплатно, без регистрации, до 10 ГБ.

Безопасная отправка больших файлов со сквозным шифрованием

Передавайте файлы до 10 ГБ бесплатно со сквозным шифрованием. Регистрация не требуется. Ваши файлы шифруются в браузере перед загрузкой — никто другой не может их прочитать.

Отправить файл