Оглавление


Введение

Данная статья предназначена для знакомства с HTTP‑заголовками безопасности и методах их использования. Я коснусь основных моментов, которые способствуют повышению безопасности при администрировании WEB‑сервера. Коснусь и постараюсь по возможности описать это доступным языком, без совсем подробного разбора «А что это такое и с чем это есть», поскольку некоторые элементы настолько обширны, что заслуживают отдельной статьи.

Короче говоря, мы будем говорить о том, как защитить веб‑морду, если на средства для этой самой защиты денег не дали, но защитить сказали. В первую очередь наши действия при такой ситуации будут подразумевать закрытие потенциально уязвимых мест на самой машине с веб‑сервером.

Про харденинг линуха уже раскрывалось ранее — тут. Но сейчас не об этом. Сейчас о том, как защититься с использованием заголовков веб‑сервера.


Заголовки HTTP

Заголовки HTTP позволяют серверу и клиенту отправлять доп. информацию вместе с HTTP‑запросом или ответом. Обмен данных соответственно происходит по протоколу HTTP, могут содержать описание данных или же информацию, необходимую для взаимодействия между клиентом и сервером.

Сгруппировать заголовки можно по следующим контекстам:

  • Основные заголовки — применяются как к запросам, так и к ответам. Не имеют отношения к данным, которые передаются в теле;

  • Заголовки запроса — содержат в основном информацию о ресурсе, который нужно получить;

  • Заголовки ответа — содержат доп. информацию об ответе. Например, о сервере, предоставившем ответ, или его местонахождении;

  • Заголовки сущности — содержат информацию о теле ресурса. Например, длину его содержимого или MIME тип.


Шифрование трафика

Передаваемые данные необходимо шифровать, чтобы, в случае перехвата этих самых данных злоумышленником, последний не смог получить информацию о взаимодействии приложения и пользователей или какую‑нибудь чувствительную информацию.

Слабое и неэффективное шифрование встречается в следующих случаях:

  • смешанный контент. То есть загрузка одних ресурсов происходит по HTTPS, а других по HTTP;

  • Слабая CORS политика (про неё будет дальше)

  • Кукисы без атрибута Secure, а также стоит определять HttpOnly

  • Использование HTTP вместо HTTPS (хотя мне кажется, сейчас это встречается крайне редко)

HSTS

HTTP Strict‑Transport‑Security — заголовок ответа, позволяющий сайту уведомить браузер о том, что доступ к ним должен быть осуществлён только посредством HTTPS вместо HTTP

Директивы:

max-age=<expire-time> — время, в секундах, которое браузер должен помнить, что сайт доступен только с помощью HTTPS.

includeSubDomains — является необязательным параметром. Если задан, то правило применяется также ко всем субдоменам сайта.

preload — является необязательным параметром. Осуществляет предзагрузку HSTS «из коробки». А если быть точнее, то из «Списка предварительной загрузки HSTS» Chrome (в других браузерах свои списки, основанные на списке Chrome).


Защита от инъекций

Поскольку веб, как правило, является достаточно открытым, то это периодически приводят к следующим клиентским уязвимостям:

По этому поводу, кстати, сейчас нами готовится подробная статья по разбору Client‑Side атак. Чтобы обезопасить себя от эксплуатации перечисленного выше на Вашем хосте рекомендуется использовать:

  • COOP;

  • CORS;

  • X-Frame-Options.

COOP

Поможет защититься от межсайтовых утечек. Заголовок Cross-Origin-Opener-Policy предоставляет сайту возможность изолироваться от перекрестных окон, открываемых с помощью window.open() или ссылки с target="_blank" без rel="noopener". В результате любое межсайтовое обращение к сайту не будет иметь на него ссылки и не сможет с ним взаимодействовать.

Директивы:

unsafe-none — это значение используется по умолчанию. Разрешает добавлять документ в контекстную группу просмотра его открывателя, если сам открыватель не имеет COOP same-origin или same-origin-allow-popups


same-origin-allow-popups — сохраняет ссылки на вновь открытые окна или вкладки, для которых либо не установлен COOP, либо они отказались от изоляции, установив для COOP значение unsafe-none.


same-origin — изолирует контекст просмотра только для сайтов одного происхождения. Перекрестные сайты не загружаются в тот же контекст просмотра.

X-Frame-Options

Заголовок морально устарел, но может использоваться для указания, разрешено ли браузеру отображать данную страницу в <frame>, <iframe>, <embed> или <object>. Такой параметр может использоваться как раз для того, чтобы предотвратить атаки типа кликджекинг, гарантируя, что их содержимое не будет встраиваться в другие сайты.

Стоит отметить, что при настроенной Content-Security-Policy, а именно наличии директивы frame-ancestors, упраздняется заголовок X-Frame-Options

Тут есть только две возможные директивы заголовка:

  • SAMEORIGIN — означает, что страница может быть отображена, только если все фреймы предшественники имеют одинаковое происхождение с самой страницей ;

  • DENY — Страница не может быть отображена в фрейме.


CORS

Cross‑Origin Resource Sharing — механизм, который использует дополнительные HTTP‑заголовки, чтобы дать пользователю возможность получать разрешение на доступ к выбранным ресурсам с сервера на источнике, который отличается от используемого в данный момент сайтом.

То есть стандарт Cross‑Origin Resource Sharing работает путем добавления новых HTTP‑заголовков, позволяющих серверам описывать, каким источникам разрешено читать информацию, запрошенную веб‑браузером.

Кроме того, для методов HTTP‑запросов, которые могут вызвать побочные эффекты на данных сервера (в частности, HTTP‑методы, отличные от GET, или POST, использующих определенные MIME‑типы), спецификация предписывает браузерам «предпросмотр» запроса, запрашивая у сервера поддерживаемые методы с помощью метода запроса OPTIONS, а затем, после «одобрения» со стороны сервера, отправляя сам запрос.

Серверы также могут информировать клиентов о необходимости отправки вместе с запросами «учетных данных» (таких как Cookies и HTTP Authentication).

Более подробно прочитать про CORS можно в следующих источниках:


CORS и CSP. Более подробно

Углубление в CORS

При изучении темы CORS можно встретить такую вещь как предварительная проверка CORS или же Preflight request. При обращении клиента к серверу браузер в первую очередь отправляет Options HTTP‑запрос, который как раз и является предварительной проверкой CORS. Уже после этого сервер отвечает списком разрешенных методов и заголовков. Далее все зависит от того, разрешено ли браузеру выполнить запрос — если разрешено, то он сразу же его выполнит, а если нет, то запрос будет не выполнен, а браузер покажет пользователю ошибку.

Для использования кросс‑доменных запросов необходимо установить соответствующие заголовки:

  • Access-Control-Allow-Origin;

  • Access-Control-Allow-Headers;

  • Access-Control-Allow-Methods;

  • Access-Control-Allow-Credentials.

Access-Control-Allow-Origin

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

Директивы:

* — указывает браузеру разрешить запросы без учетных данных из любых источников. Попытка использовать шаблон с учётными данными приведёт к ошибке;

<origin> — Указывает источник. Может быть указан только один источник. Для разрешения нескольких источников на стороне сервера необходимо наличие кода для проверки значения заголовка запроса и сравнения его со списком разрешенных доменов;

null — Определяет в качестве источника «null». Не стоит это использовать, поскольку любому источнику разрешается читать ответы на кросс‑доменные запросы.

Access-Control-Allow-Headers

Заголовок ответа используется для указание, какие HTTP заголовки могут использоваться во время запроса. Простые заголовки всегда доступны и не должны быть перечислены в списке данного заголовка.

Является обязательным, если запрос содержит заголовок Access-Control-Request-Headers.

Синтаксис:

Access-Control-Allow-Headers: <header-name>, <header-name>, ...

Access-Control-Allow-Methods

Заголовок ответа, который определяет метод или методы доступа к ресурсам. Очень полезная вещь для, чтобы не плодить ресурсы с разрешенным методом PUT.

Синтаксис:

Access-Control-Allow-Methods: <method>, <method>, ...

Access-Control-Allow-Credentials

Заголовок ответа указывает, разрешена ли отправка файлов cookie. По умолчанию: false


Углубление в CSP

Content Security Policy — используется как дополнительный уровень безопасности, который позволяет распознавать и предотвращать определенные типы атак, таких как XSS или инъекции данных. CSP описывает безопасные источники загрузки ресурсов, устанавливает правила использования встроенных стилей, скриптов. Загрузка с ресурсов, не входящих в «белый список», блокируется.

Для включения CSP необходимо настроить сервер таким образом, чтобы в ответах он использовал HTTP‑заголовок Content‑Security‑Policy.

В некоторых документации или примерах Вы можете встретить заголовок X-Content-Security-Policy. Он является устаревшим, поэтому определять его не нужно.

Альтернативной настройкой сервера для конфигурации CSP может быть использование заголовка <meta>. Выглядеть это будет, например, вот так:

<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src https://*; child-src 'none';">

Использование CSP

Настройка CSP включает в себя добавление на страницу HTTP‑заголовка Content‑Security‑Policy (en‑US) и его настройку в соответствии со списком доверенных источников, из которых пользователь может получать контент. Например, страница, на которой происходит загрузка и отображение изображений может разрешать их получение из любых источников, но ограничить отправку данных формы конкретным адресом. При правильной настройке, Content Security Policy поможет защитить страницу от атак межсайтового скриптинга (xss). Данная статья описывает как правильно настроить необходимые заголовки и примеры, как это сделать.

Перечень директив CSP можно найти тут — ссылка.

Примеры использования

Пример 1

Вы хотите ограничить источники контента только исходным сервером (исключая поддомены):

Content-Security-Policy: default-src 'self'

Пример 2

Вы хотите разрешить получение контента с доверенного домена и всех его поддоменов (доверенный домен не обязательно должен совпадать с тем, на котором настраиваются CSP):

Content-Security-Policy: default-src 'self' *.trusted.com

Пример 3

Вы хотите разрешить пользователям приложения вставлять в создаваемый ими контент картинки из любого источника, но при этом ограничить источники аудио‑ и видео‑файлов списком доверенных провайдеров. Получение скриптов должно происходить только с конкретного сервера, содержащего доверенный код.

Content-Security-Policy: default-src 'self'; img-src *; media-src media1.com media2.com; script-src userscripts.example.com

Тестирование настроек политики

Чтобы не стрелять себе в колено лишний раз стоит все внедряемое тестировать перед релизом, так ведь? Так вот для облегчения развёртывания можно настроить CSP в режиме report-only с помощью заголовка

Content-Security-Policy-Report-Only: policy

Пример:

Content-Security-Policy: default-src 'self'; report-uri http://reportcollector.example.com/collector.cgi

Таким образом политика не будет ограничивать загрузку, а в то же время будет еще и сообщать обо всех нарушениях на указанный в заголовке URI.

В том случае, если на сервере будут использоваться оба заголовка - Content-Security-Policy и Content-Security-Policy-Report-Only, то оба они будут обработаны. Соответственно политика заголовка Content-Security-Policy применится, а политика Content-Security-Policy-Report-Only создаст отчет, но не будет применена.


Заключение

Если пройтись по поверхности, то, наверное, на этом можно и заканчивать. Проверить соответствие рекомендациям безопасности, например, того же OWASP'а (OSHP) можно через следующий интрумент, сделанный как раз OWASP — Venom. Инструкции по использованию данной утилиты находятся на её странице Github. Или же можно использовать WebPageTest и Security Headers.

Статьи на Хабре по тематике:

  1. Статья на Хабре по CSP

  2. Статья на Хабре по CORS

  3. Статья на Хабре по заголовкам безопасности

4rchi

Телега со статьями и мемами

Комментарии (2)


  1. ifap
    15.10.2023 10:54
    +3

    preload - является необязательным параметром.

    Необязательным параметром является includeSubDomains а preload является несуществующим параметром, которого нет в стандарте - это частные фантазии Гугла. Впрочем, полезность HSTS сильно преувеличена: если он передается по HTTP, то, кхм, он передается только по милости MitM, а если по HTTPS, то заявляет о том, что масло - масляное.

    Дальше все не интересно до CSP, который уже неинтересен Вам, раз Вы про него толком не расказали. А про SRI вообще забыли.


  1. SUNsung
    15.10.2023 10:54
    +3

    Мда. Очередное облизывание кропсов и только.

    Лучше бы описали заголовки в целом. Какие обязательные, какие не очень. От чего может браузер делать запрос через OPTIONS и какие различия в запросах между простой загрузкой страницы и вебсокета.

    В целом вообщем затронуть заголовки. Такий статей одним куском на ру-сегменте я не встречал. А про кропсы было и будет написано 100500 статей, так как горячая возникающая у каждого новичка.