Defaults.Exposed

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 баллов, и это оценивается как проблема средней серьёзности — не потому что один заголовок сам по себе катастрофа, а потому что его отсутствие — надёжный признак, что базовые вещи не закрыты.

Во что это может вам обойтись

Это реалистичные сценарии бизнес-уровня — без театра «худшего случая».

Ничто из этого не требует изощрённого злоумышленника. Злоупотребление 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/прокси) — часто самое быстрое место, охватывающее весь сайт сразу:

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 присутствует. Кратко протестируйте сайт, чтобы убедиться, что ничего стилизованного или скриптового не сломалось — на правильно построенном сайте ничего не сломается.

Частые ошибки

Передайте это вашему ИТ-специалисту

Технический итог: эта проверка инспектирует 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.