Компании, продающие "системы показателей безопасности", сейчас на подъеме, их влияние в сфере корпоративных продаж растет. К тому же есть те, кого низкий рейтинг безопасности у продавцов смущает, и те, кто хотя бы однажды, глядя на рейтинг, отказался от покупки, — я с такими людьми общался.
Я посмотрел, как эти компании вычисляют показатели безопасности других компаний. Оказалось, они смотрят на сочетание использования НТТР-заголовка для безопасности и репутации 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.
Тут можно слегка запутаться, поэтому я составил схему — проиллюстрировать, как работает этот заголовок:
Поток данных с Access-Control-Allow-Origin
Access-Control-Allow-Origin: http://www.one.site.com
Set-Cookie
Убедитесь, что ваши 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"
Выводы
Настройка заголовков — процесс относительно простой и быстрый, зато дает прирост уровня безопасности сайта — в плане защиты данных, от межсайтового скриптинга и кликджекинга.
В будущем вы оградите себя от срыва сделок, потому что ваш рейтинг безопасности останется на уровне. Практика его оценки на основе рассмотренных мной параметров набирает обороты, и мне кажется, ее роль в ближайшие годы в сфере продаж только усилится.
Дайте знать, если я упустил какой-то важный заголовок!
Комментарии (4)
UnclShura
22.10.2019 15:33Access-Control-Allow-Origin похож на какое-то магическое заклинание, котороое на самом деле не защищает ни от чего. Что мешает свормировать HTTP запрос с «правильным» Origin?
jonie
22.10.2019 15:39+3это о браузере речь — браузер перед тем как сделать запрос (речь о js через fetch/XMLHttpRequest, не о, например img теге) с домена ХХХ на домен YYY сделает OPTIONS запрос на YYY и, если не увидит в ответе Access-Control-Allow-Origin с доменом ХХХ (ну или звездочку), то и запрос реальный делать не станет.
Руками-то собрать любой HTTP запрос и дёрнуть его не в браузере (curl например) труда не составляет, тут все упирается в браузер и его безопасность.
Например: Защищает стало быть от угона обычно токенов безопасности (того же httpOnly cookie) на чужой домен, когда сайтец выломали (на клиенте) и пытаются сделать из браузера запрос на свой домен. Проще говоря это позволяет установить доверительные отношения между от «домена-сайта» до «домена api».
chelsea2
23.10.2019 10:05-1Лучше пойти убится, чем писать такие статьи. Заголовок не отображает содержимого. Обзор 3х HTTP Headers высосан из пальца, а такое громкое название: «Полное руководство ..».
jonie
Классическая (и рабочая везде) защита от XSRF основана как раз на чтении движком скриптовым cookie, но вы это сломаете. Подобная модель, например, используется в angular, в js либе axios, да и почти всюду (в довесок к новомодным хедерам)…