Вальяжной походкой по HTTP-заголовкам
Оглавление
Введение
Данная статья предназначена для знакомства с HTTP-заголовками безопасности и методах их использования. Я коснусь основных моментов, которые способствуют повышению безопасности при администрировании WEB-сервера. Коснусь и постараюсь по возможности описать это доступным языком, без совсем подробного разбора «А что это такое и с чем это есть», поскольку некоторые элементы настолько обширны, что заслуживают отдельной статьи.
Короче говоря, мы будем говорить о том, как защитить веб-морду, если на средства для этой самой защиты денег не дали, но защитить сказали. В первую очередь наши действия при такой ситуации будут подразумевать закрытие потенциально уязвимых мест на самой машине с веб-сервером.
Про харденинг линуха уже раскрывалось ранее — тут. Но сейчас не об этом. Сейчас о том, как защититься с использованием заголовков веб-сервера.
Заголовки HTTP
Заголовки HTTP позволяют серверу и клиенту отправлять доп. информацию вместе с HTTP-запросом или ответом. Обмен данных соответственно происходит по протоколу HTTP, могут содержать описание данных или же информацию, необходимую для взаимодействия между клиентом и сервером.
Сгруппировать заголовки можно по следующим контекстам:
Основные заголовки — применяются как к запросам, так и к ответам. Не имеют отношения к данным, которые передаются в теле;
Заголовки запроса — содержат в основном информацию о ресурсе, который нужно получить;
Заголовки ответа — содержат доп. информацию об ответе. Например, о сервере, предоставившем ответ, или его местонахождении;
Заголовки сущности — содержат информацию о теле ресурса. Например, длину его содержимого или MIME тип.
Шифрование трафика
Передаваемые данные необходимо шифровать, чтобы, в случае перехвата этих самых данных злоумышленником, последний не смог получить информацию о взаимодействии приложения и пользователей или какую-нибудь чувствительную информацию.
Слабое и неэффективное шифрование встречается в следующих случаях:
смешанный контент. То есть загрузка одних ресурсов происходит по HTTPS, а других по HTTP;
Слабая CORS политика (про неё будет дальше)
Кукисы без атрибута
Secure
, а также стоит определятьHttpOnly
Использование HTTP вместо HTTPS (хотя мне кажется, сейчас это встречается крайне редко)
HSTS
HTTP Strict-Transport-Security — заголовок ответа, позволяющий сайту уведомить браузер о том, что доступ к ним должен быть осуществлён только посредством HTTPS вместо HTTP
Директивы:
max-age=
— время, в секундах, которое браузер должен помнить, что сайт доступен только с помощью 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
Заголовок морально устарел, но может использоваться для указания, разрешено ли браузеру отображать данную страницу в ,
Стоит отметить, что при настроенной 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
Заголовок ответа показывает, может ли ответ сервера быть доступен коду, отправляющему запрос с данного источника.
Директивы:
*
— указывает браузеру разрешить запросы без учетных данных из любых источников. Попытка использовать шаблон с учётными данными приведёт к ошибке;
— Указывает источник. Может быть указан только один источник. Для разрешения нескольких источников на стороне сервера необходимо наличие кода для проверки значения заголовка запроса и сравнения его со списком разрешенных доменов;
null
— Определяет в качестве источника «null». Не стоит это использовать, поскольку любому источнику разрешается читать ответы на кросс-доменные запросы.
Access-Control-Allow-Headers
Заголовок ответа используется для указание, какие HTTP заголовки могут использоваться во время запроса. Простые заголовки всегда доступны и не должны быть перечислены в списке данного заголовка.
Является обязательным, если запрос содержит заголовок Access-Control-Request-Headers
.
Синтаксис:
Access-Control-Allow-Headers: , , ...
Access-Control-Allow-Methods
Заголовок ответа, который определяет метод или методы доступа к ресурсам. Очень полезная вещь для, чтобы не плодить ресурсы с разрешенным методом PUT.
Синтаксис:
Access-Control-Allow-Methods: , , ...
Access-Control-Allow-Credentials
Заголовок ответа указывает, разрешена ли отправка файлов cookie. По умолчанию: false
Углубление в CSP
Content Security Policy — используется как дополнительный уровень безопасности, который позволяет распознавать и предотвращать определенные типы атак, таких как XSS или инъекции данных. CSP описывает безопасные источники загрузки ресурсов, устанавливает правила использования встроенных стилей, скриптов. Загрузка с ресурсов, не входящих в «белый список», блокируется.
Для включения CSP необходимо настроить сервер таким образом, чтобы в ответах он использовал HTTP-заголовок Content-Security-Policy.
В некоторых документации или примерах Вы можете встретить заголовок
X-Content-Security-Policy.
Он является устаревшим, поэтому определять его не нужно.
Альтернативной настройкой сервера для конфигурации CSP может быть использование заголовка . Выглядеть это будет, например, вот так:
Использование 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
Статьи на Хабре по тематике:
Статья на Хабре по CSP
Статья на Хабре по CORS
Статья на Хабре по заголовкам безопасности