Defaults.Exposed › Исправления › Защита от MIME-угадывания (X-Content-Type-Options)
Как исправить Защита от MIME-угадывания (X-Content-Type-Options)
Однострочный заголовок, который запрещает браузерам угадывать, что на самом деле представляет собой файл. Без него файл, загруженный кем-то на ваш сайт — или файл на ваших собственных страницах, — может быть неверно истолкован браузером и запущен как код, а это ровно тот способ, которым некоторые атаки превращают безобидную с виду загрузку в кражу сессий ваших клиентов.
Главное для вашего бизнеса: Отсутствие этого заголовка — явный, легко обнаруживаемый признак, что базовые меры не приняты. Сам по себе он редко роняет сайт, но в сочетании с формой загрузки файлов или пользовательским контентом открывает путь к запуску вредоносного кода в браузерах ваших посетителей — угону авторизованных сессий, краже данных карт или логинов и втягиванию вас в разговор об утечке данных. Это одно из самых дешёвых исправлений в безопасности: одна строка, бесплатно, около пяти минут.
Во что это может вам обойтись
- Любая страница, где клиенты или сотрудники могут загружать файлы (аватары, документы, вложения в обращения, фото объявлений), становится возможной площадкой для атак на стороне браузера.
- Злоумышленник может замаскировать вредоносный код под изображение или текстовый файл и заставить браузер посетителя запустить его — украв его авторизованную сессию на вашем сайте.
- Анкеты по безопасности, проверки киберстраховщиков и корпоративные покупатели сканируют наличие этого заголовка; его отсутствие читается как «они не делают элементарного» и может затормозить или сорвать сделку.
- Старые браузеры и некоторые интеграции «угадывают» типы содержимого и могут неправильно обработать файлы так, что это подрывает доверие или приводит к утечке данных.
Почему это важно. Браузеры, когда сервер расплывчат насчёт того, что за файл, пытаются угадать («sniff») тип содержимого. Злоумышленники этим пользуются: загружают файл, который сервер помечает как изображение, но содержимое составлено так, что браузер решает, будто это на самом деле JavaScript, — и запускает его. Заголовок X-Content-Type-Options: nosniff велит каждому браузеру прекратить угадывать и доверять заявленному сервером типу, закрывая весь этот класс уловок. Это оценочная проверка стоимостью 25 баллов, при отсутствии оценивается как средняя степень серьёзности.
Короткая версия для владельца
В каждый браузер встроено тихое допущение: скачивая файл с вашего сайта, он пытается понять, что это за файл. Обычно он доверяет вашему серверу. Но если сервер расплывчат, браузер начнёт угадывать — и это угадывание называется MIME-угадыванием (MIME-sniffing).
Проблема в том, что злоумышленники могут обыграть это угадывание. Они могут составить файл, который ваш сервер искренне считает безобидной картинкой, но который браузер, оставленный угадывать, сочтёт за фрагмент программного кода — и запустит его прямо в браузере вашего клиента, на вашем домене.
Есть однострочная инструкция, отключающая угадывание: X-Content-Type-Options: nosniff. Она велит каждому браузеру: «не угадывай — доверяй ровно тому, что говорит мой сервер». В этом всё исправление. Оно бесплатно, занимает около пяти минут и на правильно построенном сайте ничего не ломает.
Эта проверка ищет такой заголовок. Если он отсутствует, вы теряете 25 баллов, и это оценивается как проблема средней серьёзности — не потому что один заголовок сам по себе катастрофа, а потому что его отсутствие — надёжный признак, что базовые вещи не закрыты.
Во что это может вам обойтись
Это реалистичные сценарии бизнес-уровня — без театра «худшего случая».
-
«Безобидное вложение», которое им не было. Вы держите портал поддержки или маркетплейс, где клиенты загружают файлы — чеки, фото, документы. Злоумышленник загружает файл, который ваша система хранит и отдаёт как изображение. Без nosniff браузер жертвы угадывает, что файл — на самом деле скрипт, и запускает его — тихо крадя авторизованную сессию этого посетителя на вашем сайте. Теперь злоумышленник — это он: размещает заказы, читает сообщения, меняет данные. Вы узнаёте об этом, когда клиенты начинают жаловаться на действия, которых не совершали.
-
Сделка, буксующая на анкете по безопасности. Закупочная команда крупного клиента перед подписанием прогоняет автоматический скан вашего сайта. Отсутствующие заголовки безопасности всплывают мгновенно. Даже если ничего никогда не было использовано, в отчёте написано «отсутствуют базовые заголовки веб-безопасности», и вот вы уже отвечаете на вопросы об устранении и отодвигаете дату закрытия на недели — из-за исправления, которое заняло бы пять минут.
-
Усложнившееся продление киберстраховки. Всё больше страховщиков прогоняют внешние сканы перед оценкой или продлением. Чистый профиль заголовков — дешёвое доказательство гигиены; отсутствующий заголовок — маленькая чёрная метка, которая в сумме с другими подталкивает ваш тариф вверх, а условия — вниз.
-
Удар по репутации, который непросто отыграть. Если инцидент с угоном сессии приведёт к файлу, отданному с вашего домена, история звучит не как «не хватало малоизвестного заголовка», а как «[ваш бизнес] слил аккаунты клиентов». Именно эту версию запоминают клиенты, и она стоит куда дороже, чем когда-либо стоило бы исправление.
Ничто из этого не требует изощрённого злоумышленника. Злоупотребление MIME-угадыванием хорошо изучено и автоматизировано — именно поэтому сканеры так настойчиво помечают отсутствие заголовка.
Что это на самом деле
Когда браузер получает файл, сервер должен пометить его типом содержимого (например, image/png для PNG-картинки или text/html для веб-страницы). Исторически браузеры не вполне доверяли этой метке — отчасти потому, что некоторые серверы ошибались, — и заглядывали в реальные байты файла, решая сами. Это заглядывание и есть MIME-угадывание.
Удобство стало уязвимостью. Если злоумышленник может поместить файл на ваш сайт (через форму загрузки, поле комментариев, импортированный документ) и повлиять на его содержимое, он может составить нечто, что сервер пометит безобидно, но браузер угадает как исполняемый скрипт. Браузер тогда запускает его на вашем домене — со всем доверием, которое несёт ваш домен.
X-Content-Type-Options: nosniff полностью убирает угадывание. С ним браузеру сказано: используй заявленный сервером тип и ничего больше. Файл, помеченный как изображение, считается изображением, точка — даже если содержимое похоже на скрипт. Вектор атаки закрывается.
Как выглядит «хорошо»: каждый ответ вашего сайта — и страницы, и ресурсы — несёт ровно этот заголовок:
X-Content-Type-Options: nosniff
Других допустимых значений нет, настраивать нечего. Если и CDN, и сервер его добавляют (так что вы видите nosniff, nosniff) — это нормально и всё равно считается прохождением.
Как это исправить (бесплатно, ~5 минут)
Передайте этот раздел тому, кто ведёт ваш сайт, — ИТ-специалисту, веб-разработчику или поддержке хостинга. Исправление бесплатно и быстро; покупать ничего не нужно. Просьба проста: «Добавьте заголовок ответа X-Content-Type-Options: nosniff на каждую страницу и каждый ресурс сайта».
Вот детали для них, по распространённым платформам.
Cloudflare (или похожий CDN/прокси) — часто самое быстрое место, охватывающее весь сайт сразу:
- Используйте Response Header Transform Rule (Rules → Transform Rules → Modify Response Header), чтобы задать
X-Content-Type-Optionsравнымnosniffдля всех входящих запросов. Это применит его ко всему сайту, не трогая origin-сервер.
Nginx — добавьте внутри нужного блока server (или location):
add_header X-Content-Type-Options "nosniff" always;
Ключевое слово always обеспечивает отправку и на ответах с ошибками. Перезагрузите Nginx после сохранения.
Apache — требуется включённый mod_headers; в конфиге сайта или .htaccess:
Header always set X-Content-Type-Options "nosniff"
IIS / хостинг на Windows — в web.config под <system.webServer>:
<httpProtocol>
<customHeaders>
<add name="X-Content-Type-Options" value="nosniff" />
</customHeaders>
</httpProtocol>
Node / Express — задайте для каждого ответа:
app.use((req, res, next) => {
res.setHeader('X-Content-Type-Options', 'nosniff');
next();
});
(Или используйте пакет helmet, который ставит этот и ряд других заголовков безопасности по умолчанию.)
Сайты на Google Workspace / Microsoft 365: они управляют вашей почтой и документами, а не хостингом публичного сайта, поэтому заголовок там не ставится — он ставится там, где обслуживается сам сайт (ваш CDN, веб-сервер или конструктор сайтов). Если вы используете хостинговый конструктор (Squarespace, Wix, Shopify и подобные), многие добавляют этот заголовок автоматически; проверьте результат, а не предполагайте, и спросите их поддержку, если его нет.
После развёртывания проверьте. Перезапустите скан или попросите разработчика проверить заголовки ответа в инструментах разработчика браузера (вкладка Network → клик по любому запросу → Response Headers) и убедиться, что X-Content-Type-Options: nosniff присутствует. Кратко протестируйте сайт, чтобы убедиться, что ничего стилизованного или скриптового не сломалось — на правильно построенном сайте ничего не сломается.
Частые ошибки
- Установка только на главной. Заголовок должен быть на каждом ответе — включая изображения, скрипты, таблицы стилей и загруженные файлы, — потому что именно эти ресурсы затрагивает угадывание. Применяйте его на уровне сервера или CDN, чтобы он был универсальным, а не постранично.
- Опечатка в значении. Единственное допустимое значение —
nosniff. Всё остальное (пустое значение, опечатка) проваливает проверку и не даёт защиты. Сканер сообщит фактически увиденное значение, чтобы вы заметили опечатку. - Уверенность, что он заменяет Content Security Policy. nosniff — это один слой. Он не управляет тем, какие скрипты разрешено запускать — это работа CSP. Добавьте nosniff сейчас как быструю победу, а полноценный CSP воспринимайте как более крупный следующий шаг.
- Удаление «дубликата». Если и CDN, и origin его ставят, вы увидите его дважды. Это безвредно — не тратьте время на удаление одного.
- Оплата за это. Это бесплатное изменение настройки. Мониторинг, аудиты и дашборды по портфелю оплачиваются законно; добавление одного заголовка — нет.
Передайте это вашему ИТ-специалисту
Технический итог: эта проверка инспектирует HTTP-заголовки ответа и проходит, когда X-Content-Type-Options присутствует и его (регистронезависимое) значение содержит nosniff — включая многоисточниковый случай nosniff, nosniff, когда CDN и origin оба его ставят. Отсутствие или любое значение, отличное от nosniff, проваливается. Это оценочная проверка уровня P2 стоимостью 25 баллов, при провале — средняя степень серьёзности, соответствует OWASP Top 10 A05 (Security Misconfiguration). Устранение — единственный статический заголовок ответа, применённый ко всем ответам; параметров нет, допустимых альтернативных значений нет. Ставьте его на границе (CDN) для покрытия всего сайта или на веб-сервере с семантикой always, чтобы он выпускался и на ответах с ошибками, затем подтвердите в заголовках ответа.
Частые вопросы
Мы никому не разрешаем загружать файлы. Нам всё равно это нужно?
Да, и это всё равно стоит сделать. Заголовок — это эшелонированная защита: он также не даёт браузеру неправильно прочитать скрипты, таблицы стилей и файлы данных с вашего же сайта, что защищает от ряда межсайтовых атак даже на сайтах без формы загрузки. Это ничего не стоит и никогда не ломает корректно настроенный сайт, так что нет причин его пропускать.
Не сломает ли добавление этого что-нибудь на сайте?
Почти никогда. nosniff просто заставляет браузеры уважать тип содержимого, который ваш сервер уже отправляет. Единственный способ навлечь проблему — если сервер неправильно помечает файлы, например отдаёт таблицу стилей или скрипт с неверным типом. Если что-то и сломается — это реальная ошибка, которую nosniff обнажил, а не создал, и её всё равно стоит исправить. Проверьте один раз после развёртывания.
Как на самом деле выглядит «хорошо»?
Единственный заголовок ответа на каждой странице и каждом ресурсе: X-Content-Type-Options: nosniff. Это вся правильная конфигурация — других допустимых значений нет и настраивать нечего.
Наш CDN (Cloudflare или подобный) и наш сервер оба его добавляют — это проблема?
Нет. Увидеть значение дважды («nosniff, nosniff») из-за того, что и CDN, и origin его ставят, — совершенно нормально и проверку всё равно проходит. Удалять один из них не нужно.
Исправление стоит денег?
Нет. Исправление — одна строка бесплатной настройки на вашем веб-сервере или CDN. Тот, кто берёт с вас деньги за добавление одного заголовка, завышает цену. Платить в этой области имеет смысл только за постоянный мониторинг, обзор по портфелю из множества сайтов или формальный аудит — но не за само исправление.
Чем это отличается от Content Security Policy (CSP)?
Они дополняют друг друга. CSP управляет тем, какие скрипты и ресурсы вообще разрешено загружать; nosniff не даёт браузеру неверно классифицировать файл, который он уже загрузил. Нужны оба. nosniff гораздо проще и быстрее добавить, так что это хороший первый шаг на пути к полноценному CSP.