X-Content-Type-Options: nosniff
Заголовок запрещает браузеру «додумывать» тип содержимого вопреки тому, что указал сервер.
В чём проблема без него
Браузеры исторически умеют угадывать тип файла по содержимому — это называется MIME-sniffing. Задумано было ради совместимости со старыми сайтами, где типы указывали неправильно.
Атака выглядит так: злоумышленник загружает на сайт файл, который сервер считает картинкой и отдаёт с типом image/jpeg, но внутри — код JavaScript. Браузер заглядывает внутрь, решает «да это же скрипт» и выполняет его. Скрипт работает в контексте вашего домена: читает cookie, отправляет запросы от имени пользователя, подменяет содержимое страницы.
С nosniff браузер выполняет как скрипт только то, что отдано с типом application/javascript, и подключает как стиль только text/css. Файл, объявленный картинкой, останется картинкой — даже если внутри код.
Кому это нужно
Любому сайту, куда посетители могут что-то загружать: аватары, фотографии к отзывам, документы к заявкам, вложения в тикеты. Это самый частый вектор.
Но заголовок полезен и без загрузок: он дешёвый, ничего не ломает и защищает от ошибок конфигурации, при которых файлы отдаются с неверным типом.
Как включить
Nginx:
add_header X-Content-Type-Options "nosniff" always;
Apache:
Header always set X-Content-Type-Options "nosniff"
PHP (если нет доступа к серверу):
header('X-Content-Type-Options: nosniff');
Что проверить после включения
Заголовок делает браузер строгим, поэтому вылезут места, где типы указаны неправильно. Обычные жертвы: шрифты, отдаваемые как text/plain; JS-файлы с типом text/html; SVG-иконки с неверным типом. Проверьте в F12 → Network → колонка Type, что всё отдаётся корректно.
Настройка типов в nginx делается один раз через include mime.types; в конфигурации — обычно она уже есть.
Сопутствующие меры для загружаемых файлов
Заголовок — не единственная защита. Для сайтов с пользовательскими файлами стоит:
- раздавать загрузки с отдельного домена — тогда даже выполненный скрипт не получит доступа к cookie основного;
- переименовывать файлы и не доверять расширению из имени;
- пересохранять изображения — при перекодировке встроенный код не выживает;
- добавить Content-Security-Policy, которая ограничивает источники скриптов.