Security Lab

Content Sniffing через нестандартные расширения — как возникает XSS и как защититься

Content Sniffing через нестандартные расширения — как возникает XSS и как защититься

Content-sniffing — это поведение браузеров, при котором тип передаваемого ресурса определяется не только по заголовку Content-Type, но и по сигнатурам содержимого. В идеальной ситуации сервер корректно выставляет тип, и браузер следует ему. На практике ошибочные конфигурации, промежуточные узлы между приложением и пользователем (CDN, прокси), а также использование нестандартных расширений приводят к тому, что документ с «безопасным» расширением интерпретируется как активный контент (HTML, SVG, XML). В результате возникают XSS-сценарии, кража токенов и другие последствия. Ниже — системный обзор того, как возникает риск, какие есть векторы атаки и как выстроить защиту.

Что такое Content Sniffing и почему он включается

Браузеры исторически реализуют механизм определения типа ресурса на основе содержимого, чтобы обеспечивать корректный показ данных даже при некорректных заголовках. Это соответствует пользовательским ожиданиям, но для приложений создаёт дополнительную поверхность атаки. Если сервер отдал файл с неправильным Content-Type или без жёсткого запрета на «нюхание» (заголовок X-Content-Type-Options: nosniff), движок может переопределить тип, ориентируясь на первые байты и характерные маркеры формата.

  • Первопричина: несоответствие между заявленным Content-Type и реальным содержимым.
  • Условие активации: отсутствие X-Content-Type-Options: nosniff и/или слабый тип (например, text/plain) для потенциально активного контента.
  • Последствие: интерпретация файла как HTML/SVG/XML и исполнение скриптов в контексте домена, где файл опубликован.

Почему нестандартные расширения повышают риск

Расширение файла — это соглашение на уровне ОС и интерфейсов загрузки; браузер опирается на заголовки и содержимое. Нестандартные расширения (.abc, .backup, .txtx и т. п.) часто проходят фильтры, «маскируя» активный контент. Если при этом сервер отдаёт универсальный или неподходящий тип, браузер склонен «уточнять» тип по содержимому и отобразит документ, а не предложит скачивание.

  • Комбинация «нестандартное расширение + неверный Content-Type + отсутствие nosniff» создаёт условия для XSS.
  • Polyglot-файлы (валидные сразу в нескольких форматах) обходят поверхностные проверки по расширению и сигнатурам.
  • SVG обладает полноценной моделью документа; при inline- или документном рендере возможно выполнение сценариев.

Типовые сценарии эксплуатации

Ниже приведены распространённые варианты злоупотребления контент-sniffing’ом при загрузке и публикации пользовательских файлов. Примеры предназначены для осмысления рисков и выработки мер защиты в законной зоне тестирования собственных систем.

  1. Публикация загруженных файлов на том же домене.

    Пользователь загружает «отчёт.backup», фактически содержащий HTML/JS. Хранилище отдаёт файл как text/plain, заголовок nosniff отсутствует. Браузер отображает документ как HTML. Скрипт получает права того же сайта (в зависимости от политик), что ведёт к XSS и компрометации сессии.

  2. Единый хост для приложения и пользовательских файлов.

    Файлы доступны по путям вида /uploads/… на основном домене. При ошибочном Content-Type и отсутствии изоляции (куки, CSP) любой некорректно отданный файл превращается в активную страницу в доверенном контексте.

  3. Перезапись заголовков на CDN/прокси.

    Приложение формирует корректные заголовки (application/octet-stream, Content-Disposition: attachment), но промежуточный узел оптимизирует кэш и заменяет тип на text/plain, удаляя nosniff. На выходе документ отображается, а не скачивается.

  4. Inline-рендер SVG.

    SVG-файлы из пользовательских загрузок показываются как документы. При отсутствии строгих политик (CSP, sandbox) возможен запуск сценариев и XSS.

  5. Polyglot-файлы.

    Файл, совмещающий сигнатуру изображения и корректный HTML, проходит поверхностные фильтры и при этом интерпретируется браузером как HTML-документ.

Диагностика: как выявить уязвимость в своей системе

Рекомендуется проводить тесты в контролируемой среде и в пределах правомерного периметра. Цель — проверить, как система обрабатывает спорные типы файлов и какие заголовки реально доходят до клиента.

  1. Набор контрольных образцов.
    • HTML с нестандартным расширением (.abc, .backup и т. п.).
    • SVG c безопасным маркером (например, вывод в консоль).
    • Polyglot (минимальная сигнатура изображения + HTML-тело) — только в лабораторных стендах.
  2. Анализ ответов.
    • Проверьте Content-Type, Content-Disposition, X-Content-Type-Options, Content-Security-Policy.
    • Откройте прямую ссылку и зафиксируйте поведение: скачивание или отображение.
  3. Сквозная проверка цепочки доставки.
    • Проверьте, не модифицируют ли CDN/прокси итоговые заголовки.
    • Сравните поведение в основных браузерах (Chrome, Firefox, Safari).
  4. Проверка доменной изоляции.
    • Выясните, с какого хоста отдаются пользовательские файлы (тот же домен/поддомен/отдельный домен).
    • Проверьте, применяются ли для этого хоста куки и политики основного приложения.

Полезные инструменты: Burp Suite, OWASP ZAP, DevTools браузеров, а также сервисы оценки заголовков: SecurityHeaders, Mozilla Observatory.

Ограничения «nosniff» и связанные особенности форматов

X-Content-Type-Options: nosniff отключает эвристику sniffing’а и заставляет браузер доверять указанному Content-Type. Однако при слабом типе и отсутствии других мер защита будет неполной. Аналогично, форматы, способные содержать активный контент (SVG, некоторые случаи PDF/XML), требуют дополнительных ограничений даже при корректных типах.

  • Выставляйте корректный Content-Type и дополняйте его nosniff.
  • Для потенциально активного содержимого используйте Content-Disposition: attachment.
  • Контролируйте поведение промежуточных узлов, которые могут переписывать заголовки.

Справочная информация: MDN: X-Content-Type-Options.

Анти-паттерны конфигурации

  • Единый домен для приложения и пользовательских файлов без CSP и sandbox.
  • Использование универсального типа (application/octet-stream) для разнотипных ресурсов без Content-Disposition: attachment.
  • Фильтрация только по расширению или только по магическим байтам без валидации структурного формата.
  • Inline-рендер пользовательских SVG/HTML без очистки и без изоляции.
  • Доверие к «умным» функциям CDN, которые могут модифицировать заголовки без явного контроля.

Комплексная стратегия защиты

Эффективная защита опирается на сочетание изоляции, корректной типизации, принудительного скачивания и политик браузера. Ниже — практический набор мер.

  1. Изоляция пользовательских файлов по доменам.

    Размещайте пользовательские загрузки на отдельном домене/поддомене, не разделяющем куки с приложением (например, files.exampleusercontent.com). Это снижает привилегии контента, даже если он будет отображён как документ.

  2. Корректный Content-Type и запрет sniffing’а.
    • Назначайте точные типы для поддерживаемых форматов.
    • Устанавливайте X-Content-Type-Options: nosniff для всех ответов со статикой и загрузками.
  3. Принудительное скачивание активных форматов.
    • Используйте Content-Disposition: attachment; filename="..." для HTML, SVG, XML, а также для PDF при сомнениях.
    • Не рендерьте пользовательские файлы inline без необходимости и без очистки.
  4. Валидация содержимого.
    • Проверяйте структуру файлов и используйте библиотечные декодеры.
    • Для изображений применяйте «перепаковку» (re-encode) в доверенный формат на сервере, отбрасывая нестандартные сегменты.
  5. Политики браузера (CSP и сопутствующие).

    Вводите строгую Content-Security-Policy для доменов приложения и доменов, где возможен показ контента. Запрещайте inline-скрипты и eval, ограничивайте источники. Справочник: MDN: CSP.

  6. Контроль поведения CDN/облака.

    На уровне S3/аналогов задавайте метаданные объектов с точным типом и Content-Disposition. На edge (CloudFront/Cloudflare/Fastly) явно запрещайте переписывание критичных заголовков и проверяйте предпросмотр.

  7. Автоматизация контроля.

    Добавьте в CI/CD тесты заголовков и поведение при открытии файлов. Регулярно прогоняйте DAST на ключевых путях доставки файлов.

Чек-лист для Dev, DevOps и AppSec

  • Пользовательские файлы отдаются с отдельного домена/поддомена без общих кук с основным приложением.
  • Каждый формат имеет корректный Content-Type, отсутствуют «универсальные» значения без необходимости.
  • X-Content-Type-Options: nosniff включён для статических и файловых ответов.
  • Content-Disposition: attachment применяется к потенциально активным форматам.
  • SVG из пользовательских загрузок запрещён для inline-рендера, либо конвертируется в растр.
  • CDN/прокси не модифицируют критичные заголовки (проверено сквозными тестами).
  • Действует CSP без unsafe-inline и unsafe-eval, источники скриптов строго ограничены.
  • В CI/CD есть smoke-тесты на заголовки и фактическое поведение браузера.

Разбор критичных комбинаций

HTML под нестандартным расширением

Файл «report.backup» содержит HTML. Сервер отдаёт ответ с Content-Type: text/plain, заголовок nosniff отсутствует. Часть браузеров интерпретирует содержимое как HTML-документ. Меры: корректный тип (или преднамеренно «неотображаемый»), обязательный nosniff, Content-Disposition: attachment и доменная изоляция.

SVG в качестве документа

SVG способен включать сценарии и ссылки на внешние ресурсы. При показе как документ возможна XSS. Рекомендация: не отображать пользовательские SVG inline; при необходимости — конвертировать в растровое изображение на серверной стороне и отдавать как вложение.

Polyglot: изображение + HTML

Polyglot может пройти упрощённую проверку сигнатур и быть интерпретирован браузером как HTML. Единственный надёжный подход — отказ от inline-рендера пользовательских файлов, re-encode изображений и корректные заголовки.

Тестирование: порядок работ

Организуйте тестирование в рамках утверждённых стендов. Цель — подтвердить или опровергнуть возможность отображения пользовательских файлов как активного контента.

  1. Определите все точки выдачи файлов (прямые ссылки, предпросмотры, API с range-запросами, CDN-путь).
  2. Сформируйте набор контрольных образцов (HTML, SVG, polyglot) под разными расширениями.
  3. Проверьте заголовки ответа и фактическое поведение в основных браузерах.
  4. Повторите проверки через внешний периметр (CDN/прокси), сравните заголовки end-to-end.
  5. Задокументируйте расхождения и внесите изменения в конфигурации приложений и edge-слоя.

Справочники и инструменты: OWASP File Upload Cheat Sheet, OWASP Top 10, MDN: MIME types.

Настройки заголовков и политик

Сконцентрируйтесь на следующих элементах конфигурации. Они не взаимозаменяемы и дают эффект в совокупности.

  • X-Content-Type-Options: nosniff — запрещает браузеру переопределять тип ресурса по содержимому.
  • Content-Type — должен соответствовать реальному формату и быть единообразным в системе.
  • Content-Disposition: attachment — переводит потенциально опасные форматы в режим скачивания.
  • Content-Security-Policy — ограничивает источники сценариев/фреймов и снижает ущерб даже при ошибочном отображении.
  • Cross-Origin-политики (CORP/COOP/COEP) — усиливают изоляцию границ процессов и ресурсов.
  • Referrer-Policy — минимизирует сопутствующие утечки метаданных.

Облачные хранилища и CDN

Частая причина проблем — отличие реальной выдачи от ожиданий конфигурации приложения. Необходимо жёстко фиксировать метаданные объектов и правила на edge-уровне.

  • Для объектов S3/аналогов задавайте явные metadata: Content-Type и Content-Disposition.
  • На edge (CloudFront/Cloudflare/Fastly) запрещайте перезапись критичных заголовков; отключайте предпросмотр, который может отображать SVG/HTML как документ.
  • Регулярно проводите сквозные проверки, сверяя заголовки ответа приложения и итоговые заголовки на клиенте.

Баланс UX и безопасности

В ряде сценариев пользователю нужен предпросмотр документов в браузере. Обеспечьте контроль за тем, какой контент может рендериться inline и в каком контексте.

  • Inline-просмотр разрешайте только для доверенных форматов, генерируемых системой (например, PDF из вашего генератора, изображения после re-encode).
  • Внешние загрузки отображайте только после нормализации/санитизации; допускайте рендер в iframe с sandbox и на отдельном домене.
  • Для «серых зон» применяйте attachment и отказ от inline-показа.

План внедрения за один спринт

Реалистичный порядок действий, позволяющий существенно снизить риск без долгих проектов.

  1. Инвентаризация. Соберите перечень всех маршрутов выдачи файлов, статических и пользовательских. Зафиксируйте текущие заголовки.
  2. Базовые правки. Включите nosniff, выровняйте Content-Type, добавьте Content-Disposition: attachment для активных форматов.
  3. Изоляция. Перенесите пользовательские файлы на отдельный домен/поддомен, настройте CSP, запретите inline-SVG.
  4. Нормализация изображений. Добавьте серверный re-encode для пользовательских изображений.
  5. Edge-контроль. Зафиксируйте правила на CDN/прокси, исключающие перепись заголовков.
  6. Автотесты. Включите проверки заголовков и сценариев открытия в CI/CD для ключевых маршрутов.

FAQ

  • Достаточно ли включить nosniff? Недостаточно. Нужны корректные типы, attachment для активных форматов, изоляция доменов и политика CSP.
  • Даст ли фильтрация по расширению гарантию? Нет. Расширение легко подменяется и не отражает фактическое содержимое.
  • SVG можно показывать inline? Рекомендуется запрещать inline-рендер пользовательских SVG. При необходимости — конвертация в растр и/или рендер в изолированном iframe на отдельном домене.
  • PDF безопасен по умолчанию? Не всегда. Зависит от рендерера и контекста. Для пользовательских PDF целесообразно использовать attachment либо доверенный просмотрщик в изолированном контексте.

Рекомендуемые материалы и инструменты

Выводы

Content-sniffing сам по себе не является дефектом, но в сочетании с неправильными заголовками и отсутствием изоляции создаёт существенные риски. Эксплуатация через нестандартные расширения — распространённая практика, основанная на расхождении между заявленным типом и фактическим содержимым. Снижение риска достигается комбинацией мер: изоляцией пользовательских файлов на отдельном домене, корректной типизацией и запретом sniffing’а, принудительным скачиванием активных форматов, применением строгой CSP, нормализацией изображений и жёстким контролем поведения CDN/прокси. Регулярная автоматизированная проверка заголовков и сценариев рендеринга должна стать обязательной частью CI/CD.

ContentSniffing ContentType CSP FileUpload MIME MIMEsniffing nosniff SVGsecurity WebSecurity XSS
Alt text
Обращаем внимание, что все материалы в этом блоге представляют личное мнение их авторов. Редакция SecurityLab.ru не несет ответственности за точность, полноту и достоверность опубликованных данных. Вся информация предоставлена «как есть» и может не соответствовать официальной позиции компании.

А что, если карьерный тупик — это миф?

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