- PVSM.RU - https://www.pvsm.ru -
Одним из приоритетов для команды Яндекс.Почты всегда была и есть безопасность данных пользователя. Причем это касается не только хранения писем, но и безопасного доступа к ним. Еще в 2011 году мы стали пропускать все изображения в письмах через наши прокси-сервера, перекрыв один из каналов распространения вредоносного кода, а также кешировать их для экономии трафика и обеспечения большей приватности. В ноябре этого года мы внедрили шифрование при приеме и отправке почты, а также и перевели почту в режим HTTPS-only — теперь веб-интерфейс доступен только по безопасному протоколу.
А с недавних пор мы стали поддерживать новый механизм защиты данных пользователя – стандарт Content Security Policy. С его помощью можно запретить скриптам на странице подгружать какие-либо ресурсы с хостов, не указанных в белом списке.
Это пока довольно редкая штука (ни одна крупная известная нам почта этого ещё не применяет), и в этом посте мы поделимся опытом внедрения стандарта.
[1]
XSS [2], несмотря на всю изученность, является одной из самых распространенных уязвимостей сайтов. Эта уязвимость позволяет злоумышленнику вставить вредоносный код на страницу веб-приложения. Как контролировать это на сервере, мы прекрасно знаем. А вот на пользовательской стороне с этим все несколько сложнее.
Какие методы защиты мы знаем?
Теперь появился еще один механизм защиты от такого рода атак — Content Security Policy
Content Security Policy (CSP [3]) — новый стандарт, определяющий HTTP-заголовки Content-Security-Policy и Content-Security-Policy-Report-Only, которые сообщают браузеру белый список хостов, с которых он может загружать различные ресурсы.
Текущий статус стандарта [4] — Candidate Recommendation.
На сегодняшний день его поддерживают все популярные браузеры:
Для ознакомления можно почитать на HTML5 Rocks статью [5]Майка Уэста (Mike West) — одного из разработчиков стандарта. Хорошее описание стандарта есть на MDN [6].
Заголовок CSP состоит из набора разделенных директив — частей политики, контролирующих определенные ресурсы браузера.
{
"csp-report": {
"document-uri": "https://mail.yandex.ru/neo2/",
"referrer": "http://www.yandex.ru/",
"violated-directive": "script-src 'unsafe-inline' 'unsafe-eval' blob: chrome-extension: *.yandex.ru *.yandex.net yandex.st",
"original-policy": ".... здесь указана все политики ...",
"blocked-uri": "... урл заблокированного ресурса ..."
}
}
Некоторые браузеры также указывают в отчете ссылку и строку JS, которые привели к нарушению политики безопасности.
Кроме того, в директивах можно использовать не хосты, а ключевые слова (обязательно в кавычках):
<script>, javascript: и инлайн-обработчики событий (onclick=""). Для style-src разрешает использование тега <style> и атрибута style="". По возможности старайтесь не указывать это ключевое слово, т.к. это напрямую разрешает исполнять любой инлайн javascript на странице, что может приводить к XSS.Хосты можно указывать как просто "yandex.st", так и с протоколом или портом "https://yandex.st:443". Помните, что если у хоста не указан протокол или порт, то он берется из текущей страницы, по аналогии с same origin policy. Таким образом, хост "yandex.st" на странице "https://mail.yandex.ru:443/neo2/" автоматически приобретет вид "https://yandex.st:443".
Если указан заголовок Content-Security-Policy, то браузер блокирует все ресурсы, которые не соответствуют политике. Заголовок Content-Security-Policy-Report-Only также проверяет все ресурсы, но не блокирует их, а только сообщает о нарушениях. Мы рекомендуем его использовать на первых этапах внедрения CSP.
Мы исследовали эту технологию с весны, когда еще не было ни одной стандартной реализации. Сначала аккуратно внедрили заголовок Content-Security-Policy-Report-Only для нашей внутренней почты. Некоторые время мы изучали отчеты и исправляли нашу политику, и уже в мае включили CSP в блокирующем режиме. Во время внутреннего тестирования исследовалось поведение всех заголовков — и стандартных, и нет.
С публичной почтой было несколько труднее, ведь к нам приходили пользователи с неконтролируемым окружением. Несколько месяцев мы разбирались в отчетах, исправляли политики, и, наконец, осенью выкатили их на 100% в блокирующем режиме.
Самое интересное, что мы теперь имеем — несколько миллионов ежедневных отчетов с нарушениями от вирусов, нерадивых плагинов и расширений, которые пытаются вставлять свой код на наши страницы. Мы не можем контролировать содержимое этого кода, а значит не можем гарантировать, что он бережно относится к персональным данным наших пользователей — и довольны тем, что блокируем их исполнение.
Кроме того, в процессе внедрения мы разработали инструменты для работы с CSP:
Разберем заголовок на примере мобильной Яндекс.Почты
// разрешаем соединение с собственным хостом, yandex.st и подключения по WebSocket к xiva-daria.mail.yandex.net
Content-Security-Policy: default-src 'self' wss://xiva-daria.mail.yandex.net yandex.st;
// разрешаем собственные домены для подновления кук при длительной работе
frame-src *.yandex.ru;
// 'self' data: для inline-картинок
// mc.yandex.ru — Яндекс.Метрика
// yandex.st — наш CDN со статикой
// *.yandex.net - аватарки и https-кешер
img-src 'self' data: mc.yandex.ru *.yandex.net yandex.st;
// шрифтов и плагинов у нас нет
font-src 'none';
object-src 'none';
// 'unsafe-inline' — мы используем inline-стили для анимации переходов между страницами
// yandex.st — наш CDN со статикой
style-src 'unsafe-inline' yandex.st;
// self и blob — для разрешения выполнения js через blob
// unsafe-eval потому что мы используем кодогенерацию
// mc.yandex.ru — Яндекс.Метрика
// yandex.st — наш CDN со статикой
script-src 'self' 'unsafe-eval' blob: mc.yandex.ru yandex.st;
// обязательно указываем урл для отчетов
report-uri /neo2/csp.jsx?from=touch
Примерный план внедрения CSP на сервисе выглядит следующим образом:
Особенности браузеров:
Мы не рекомендуем использовать нестандартные заголовки. Последние версии современных браузеров (за исключением IE) поддерживают стандартный заголовок, поэтому, используя только его, вы покрываете подавляющую часть аудитории.
Особенности CSP, о которых нужно всегда помнить:
Естественно, это не всегда возможно, но старайтесь не использовать *, а указывайте точный список доменов. Также указывайте все директивы, иначе все ошибки будут сыпаться как нарушение в default-src. Конечно, размер заголовка увеличиться, зато найти проблемы будет намного проще.
К сожалению, нам пока не удалось отказаться от unsafe-inline. Инлайн-скрипты в почте используются для двух вещей: выдача настроек и проверка загрузки критичных JS (jQuery и загрузчика). И если настройки мы могли переделать на JSON, то отказаться от важных отчетов незазгрузки JS мы не смогли, и пришлось оставить 'unsafe-inline'. Также проблем добавило активное использование инлайн-атрибутов в WYSWYG-редакторе TinyMCE.
Хоть такое правило и позволяет исполнять любой инлайн javascript на странице, мы можем обезопасить себя тем, что разрешаем соединение только с проверенными ресурсами.
Новая версия стандарта на текущий момент находится в стадии черновика, но Chrome и Firefox уже начинают внедрять новые возможности из него.
Например, новая директива nonce может стать решением неудобства с полным запретом unsafe-inline. Схема работы пока находится в стадии разработки, но мы прикладываем усилия, чтобы он работал следующим образом:
Пример:
Content-Security-Policy: default-src 'self'; script-src 'self' https://example.com 'nonce-eef8264c4994bf6409c51ac7c9614446'
<script>
alert("Заблокирован, отсутствует атрибут nonce")
</script>
<script nonce="22168992a8d57a5d3a64ca73bb9fc669">
alert("Заблокирован, потому что атрибут nonce не совпадает")
</script>
<script nonce="eef8264c4994bf6409c51ac7c9614446">
alert("Выполнен, потому что атрибут nonce валиден")
</script>
<!-- валиден, потому что в script-src есть https://example.com -->
<script src="https://example.com/allowed-because-of-src.js"></script>
<!-- Заблокирован, потому что атрибут nonce не совпадает -->
<script nonce="22168992a8d57a5d3a64ca73bb9fc669" src="https://otherdomain.com/invalid.js"></script>
<!-- Выполнен, потому что атрибут nonce совпадает, несмотря на то, что otherdomain.com нет в директиве script-src -->
<script nonce="eef8264c4994bf6409c51ac7c9614446" src="https://otherdomain.com/valid.js"></script>
Также CSP 1.1 добавляет новые возможности:
CSP оказался не только защитой от атак и блокированием непонятных запросов. В тестировании нас приятно удивили две вещи:
Пробуйте CSP, внедряйте, защищайте личные данные пользователей и просто делайте мир лучше.
Автор: doochik
Источник [12]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/bezopasnost/51032
Ссылки в тексте:
[1] Image: http://habrahabr.ru/company/yandex/blog/206508/
[2] XSS: http://ru.wikipedia.org/wiki/%CC%E5%E6%F1%E0%E9%F2%EE%E2%FB%E9_%F1%EA%F0%E8%EF%F2%E8%ED%E3
[3] CSP: http://en.wikipedia.org/wiki/Content_Security_Policy
[4] стандарта: http://www.w3.org/TR/CSP/
[5] статью : http://www.html5rocks.com/en/tutorials/security/content-security-policy/
[6] MDN: https://developer.mozilla.org/en-US/docs/Security/CSP
[7] Расширение: https://github.com/oxdef/csp-tester
[8] Утилита: https://github.com/oxdef/csp-reporter/
[9] вики Mozilla: https://wiki.mozilla.org/Security/CSP/Specification
[10] проблемы: https://bugzilla.mozilla.org/show_bug.cgi?id=820719
[11] jQuery < 1.8: http://bugs.jquery.com/ticket/12040
[12] Источник: http://habrahabr.ru/post/206508/
Нажмите здесь для печати.