Полное руководство по настройке HTTP-заголовков для безопасности

в 8:25, , рубрики: devops, http, ip reputation, security, security headers, Блог компании Southbridge, Серверное администрирование, системное администрирование

Полное руководство по настройке HTTP-заголовков для безопасности - 1

Компании, продающие "системы показателей безопасности", сейчас на подъеме, их влияние в сфере корпоративных продаж растет. К тому же есть те, кого низкий рейтинг безопасности у продавцов смущает, и те, кто хотя бы однажды, глядя на рейтинг, отказался от покупки, — я с такими людьми общался.

Я посмотрел, как эти компании вычисляют показатели безопасности других компаний. Оказалось, они смотрят на сочетание использования НТТР-заголовка для безопасности и репутации IP-адресов.

Репутация IP-адреса основывается на данных черных списков и списков спамеров в сочетании с данными о владельце общедоступного IP-адреса. Она, в принципе, должна быть чистой, если ваша компания не рассылает спам и в состоянии быстро определить и остановить вредоносное внедрение. Использование заголовка безопасности НТТР вычисляется аналогично тому, как работает Observatory от Mozilla.

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

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

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

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

Важные заголовки для безопасности

Content-Security-Policy

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

Для предварительной версии можно использовать замечательный инструмент — расширение для браузера Mozilla, Laboratory CSP. Установите его в браузере, тщательно изучите сайт, для которого хотите создать CSP, а после используйте сгенерированную CSP на своем сайте. В идеале, нужно еще переработать JavaScript, так что можно удалить директиву «unsafe inline».

CSP может показаться сложной и сбить с толку, поэтому, если хотите углубиться в тему, посетите официальный сайт.

Предварительно можно настроить CSP так (на боевом сайте она, скорее всего, потребует множества модификаций). Добавьте в каждый раздел вашего сайта домены.

# Default to only allow content from the current site
# Allow images from current site and imgur.com
# Don't allow objects such as Flash and Java
# Only allow scripts from the current site
# Only allow styles from the current site
# Only allow frames from the current site
# Restrict URL's in the <base> tag to current site
# Allow forms to submit only to the current site
Content-Security-Policy: default-src 'self'; img-src 'self' https://i.imgur.com; object-src 'none'; script-src 'self'; style-src 'self'; frame-ancestors 'self'; base-uri 'self'; form-action 'self';

Strict-Transport-Security

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

Strict-Transport-Security: max-age=3600; includeSubDomains

X-Content-Type-Options

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

Также он снижает риск неожиданного поведения приложения, когда браузер неверно "угадывает" тип контента на сайте — например, если разработчик обозначает страницу "HTML", а браузер видит JavaScript и пытается отрисовать страницу соответственно. Также благодаря этому заголовку браузер всегда держится установленных сервером MIME-типов.

X-Content-Type-Options: nosniff

Cache-Control

Этот будет позаковыристее прочих, потому что для разных типов контента вам наверняка нужны разные политики кэширования.

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

Впрочем, кэшировать можно и нужно те страницы, которые обновляются редко, например статические ресурсы (картинки, файлы CSS и JS). Кэширование можно настроить на постраничной основе, или используя regex в настройках сервера.

# Don’t cache by default
Header set Cache-Control no-cache

# Cache static assets for 1 day
<filesMatch ".(css|jpg|jpeg|png|gif|js|ico)$">
    Header set Cache-Control "max-age=86400, public"
</filesMatch>

Expires

Этот заголовок устанавливает время, на которое текущий запрос сохраняется в кэше. Он игнорируется, если включен заголовок Cache-Control max-age, так что мы включаем его только на случай, если его проверяет простенький сканер — без учета контроля кэширования.

Мы предполагаем, что в целях безопасности браузер не кэширует ничего, так что дата в заголовке всегда будет в прошлом.

Expires: 0

X-Frame-Options

Этот заголовок разрешает отображение сайта в iFrame.

Поместив ваш веб-сайт в iFrame, вредоносный ресурс получает возможность произвести кликджекинг атаку — запустив некий JavaScript, который обманом вынудит пользователя кликнуть по iFrame, а после начнет взаимодействовать с ресурсом от его, пользователя, имени (то есть человек кликнет по вредоносной ссылке или кнопке, даже не подозревая об этом!).

Этот заголовок всегда надо настраивать на отказ, исключение — если вы намеренно используете фреймы. Тогда заголовок нужно настраивать на тот же источник. Если вы по умолчанию используете фреймы с другим сайтом, занесите сторонний домен в белый список.

Следует также отметить, что этот заголовок замещается директивой CSP frame-ancestors. Я его рекомендую пока включать, но только для того, чтобы заткнуть инструменты для проверки заголовков, в будущем от него скорее всего избавятся.

X-Frame-Options: deny

Access-Control-Allow-Origin

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

Например, сайт А содержит некий JavaScript, который хочет сделать запрос к сайту В. Сайт В должен ответить на этот запрос — если заголовок разрешает сайту А сделать запрос. Если нужно настроить множество источников, подробности на странице на MDN.

Тут можно слегка запутаться, поэтому я составил схему — проиллюстрировать, как работает этот заголовок:

Полное руководство по настройке HTTP-заголовков для безопасности - 2
Поток данных с Access-Control-Allow-Origin

Access-Control-Allow-Origin: http://www.one.site.com

Убедитесь, что ваши cookies устанавливаются только через протокол HTTPS (с шифрованием), и что к ним нет доступа через JavaScript. Эти файлы можно посылать, только если ваш сайт тоже поддерживает HTTPS, как и должно быть. Всегда нужно выставлять вот такие флаги:

  • Secure
  • HTTPOnly

Пример определения Cookie:

Set-Cookie: <cookie-name>=<cookie-value>; Domain=<domain-value>; Secure; HttpOnly

Подробнее — в отличной документации по cookies от Mozilla.

X-XSS-Protection

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

X-XSS-Protection: 1; mode=block

Пример настроек веб-сервера

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

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

Конфигурация Apache

Пример настройки Apache в .htaccess:

<IfModule mod_headers.c>
    ## CSP
    Header set Content-Security-Policy: default-src 'self'; img-src 'self' https://i.imgur.com; object-src 'none'; script-src 'self'; style-src 'self'; frame-ancestors 'self'; base-uri 'self'; form-action 'self';

    ## General Security Headers
    Header set X-XSS-Protection: 1; mode=block
    Header set Access-Control-Allow-Origin: http://www.one.site.com
    Header set X-Frame-Options: deny
    Header set X-Content-Type-Options: nosniff
    Header set Strict-Transport-Security: max-age=3600; includeSubDomains

    ## Caching rules
    # Don’t cache by default
    Header set Cache-Control no-cache
    Header set Expires: 0

    # Cache static assets for 1 day
    <filesMatch ".(ico|css|js|gif|jpeg|jpg|png|svg|woff|ttf|eot)$">
        Header set Cache-Control "max-age=86400, public"
    </filesMatch>

</IfModule>

Конфигурация Nginx

## CSP
add_header Content-Security-Policy: default-src 'self'; img-src 'self' https://i.imgur.com; object-src 'none'; script-src 'self'; style-src 'self'; frame-ancestors 'self'; base-uri 'self'; form-action 'self';

## General Security Headers
add_header X-XSS-Protection: 1; mode=block;
add_header Access-Control-Allow-Origin: http://www.one.site.com;
add_header X-Frame-Options: deny;
add_header X-Content-Type-Options: nosniff;
add_header Strict-Transport-Security: max-age=3600; includeSubDomains;

## Caching rules
# Don’t cache by default
add_header Cache-Control no-cache;
add_header Expires: 0;

# Cache static assets for 1 day
location ~* .(?:ico|css|js|gif|jpe?g|png|svg|woff|ttf|eot)$ {
    try_files $uri @rewriteapp;
    add_header Cache-Control "max-age=86400, public";
}

Настройка заголовка уровня приложения

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

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

Node и express:

Добавьте global mount path:

app.use(function(req, res, next) {
    res.header('X-XSS-Protection', 1; mode=block);    
    next();
});

Java и Spring

У меня мало опыта работы со Spring, но у Baeldung есть отличное руководство по настройке заголовков в Spring.

PHP

Я не знаком с разнообразными средами PHP. Ищите промежуточное ПО для запросов. Для единичного запроса все просто.

header("X-XSS-Protection: 1; mode=block");

Python / Django

Django включает настраиваемое промежуточное ПО для обеспечения безопасности, которое выполнит за вас все эти настройки. Активируйте сначала их.

Ответы некоторых страниц можно трактовать как словарь. В Django есть особый способ работы с кэшированием, и если хотите настроить заголовки кэширования таким образом, с ним надо ознакомиться.

response = HttpResponse()
response["X-XSS-Protection"] = "1; mode=block"

Выводы

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

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

Дайте знать, если я упустил какой-то важный заголовок!

Автор: nAbdullin

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js