Компания
1 233,96
рейтинг
14 ноября 2012 в 14:14

Разное → Силовые тренировки: раскатываем HTTPS под высокими нагрузками

В сентябре Почта Mail.Ru включила HTTPS-шифрование для всех пользователей.

Преимущества защищенного соединения очевидны всем разработчикам крупных интернет-проектов. Большинство современных web-серверов (nginx, Apache, etc) и браузеров поддерживают HTTPS. В то же время сайтов, на которых безопасный протокол включен всегда и по умолчанию, не так много. Почему это так? С какими трудностями мы столкнулись при поддержке HTTPS? Читайте под катом.

Особенности работы SSL на высоконагруженных системах

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

Что нужно сделать, чтобы поддержать SSL?

Казалось бы, достаточно заказать сертификат, разложить его на серверы, включить опцию в nginx, — и добро пожаловать в мир защищенного трафика. Но в реальности все не так просто. Вернее, не так: все было бы просто, если бы нам зачем-то потребовалось обезопасить статическую страничку с текстом «Hello world». А вот для высоконагруженной системы с большим количеством разнообразного контента, какой является Почта Mail.Ru, все самое интересное начинается как раз после того, как сертификаты уже приобретены и разложены.

В чём отличие Почты Mail.Ru от гипотетической страницы с «Hello world»? По сути, с точки зрения поддержки HTTPS основных отличий два. Во-первых, Почта содержит множество страниц – десятки: список писем, сами письма, настройки, адресную книгу, и т.д., и на каждой странице сотни элементов (картинки, JS-ники, CSS-ы и т.д.). Во-вторых, Почта работает под гигантской нагрузкой, обрабатывая сотни тысяч HTTP-запросов в секунду (включая, разумеется, и запросы на статику). Вот из-за этих двух аспектов реализация поддержки HTTPS и была такой непростой.

Как эти аспекты влияют на поддержку? Первый аспект влияет следующим образом: когда страница одна, у сервера есть сертификат, браузер его понимает, всё работает. Проблемы начинаются в том случае, когда страниц много и, более того, когда на этих страницах есть внешние элементы, которые выполняются в контексте этой страницы. Браузер считает, что соединение безопасное, только если все элементы до последнего на странице были отданы по безопасному протоколу: это касается всех картинок, JS, CSS и т.д. Если хоть один элемент был отдан по небезопасному протоколу, браузер будет считать небезопасной всю страницу целиком и информировать об этом пользователя.

Вторая проблема, которую создает большая нагруженность Почты, состоит в том, что шифрование и дешифрование достаточно дорогая операция — как с точки зрения процессора, так и с точки зрения памяти. Процессорное время тратится на шифрование и дешифрование. Память тратится на SSL-кэш, увеличенные буферы nginx-а, большое количество воркеров веб-серверов, которые дольше висят в памяти из-за более долгой обработки запросов. SSL – это такой зверь, который съест много «камня» и памяти и не подавится при этом.

Как с этим бороться?

Баннерная система

Почта — это гетерогенная конструкция. У нас есть собственная баннерная система. Это не только почтовая система, а общая баннерная система портала Mail.Ru, которая ничего ни о каком HTTPS не слышала. Учитывая, что нам пришлось отдавать по HTTPS вообще все данные со всех страниц, баннерную систему пришлось существенно доработать.

Помимо того, что мы научили веб-серверы отдавать по HTTPS все баннеры, скрипты и статику, нам пришлось иметь дело с партнерскими пикселями. Пиксель — это картинка 1х1, которую предоставляет партнер, и которая дергается в тех случаях, когда показывается баннер. Надо отметить, что далеко не все наши партнеры работают по HTTPS, а, как я уже отмечал, небезопасных элементов на странице быть не должно, даже если они размером 1х1 пиксель. Можно было, конечно, пропускать все пиксели через прокси, но мы пошли сначала более простым путем. Договорились с партнерами, объяснили им, насколько это все замечательно и нужно, и теперь они поставляют нам HTTPS-ные пиксели. Дело это было, понятно, непростое, но это сработало. Правда, теперь необходимо и новых партнеров учить тому, что ссылка на картинку должна быть безопасной.

С баннерами есть еще одна проблема: их могут вводить не только технические специалисты, но другие сотрудники с различным уровнем компьютерной грамотности. Соответственно, существует вероятность, что вместе с баннером на странице вполне могут появиться не SSL-ные картинки, JS-ы, небезопасные счётчики.

Для решения этой проблемы мы единоразово прошлись по всем баннерам и заменили все небезопасные на безопасные. Однако это не даёт гарантии, что в будущем ничего не поменяется. Поэтому мы сделали доработку в баннерной системе: создали бит SSL-ready, который назначается каждому проекту. Пока он установлен только у Почты. Наличие этого бита говорит о том, что на этом проекте не будут показывать баннеры, в которых есть небезопасный контент. Всем баннерам, которые показывались в Почте, также проставлялся бит SSL-ready. И наша система для таких баннеров запрещает на уровне ввода в админку менять безопасный контент на небезопасный или добавлять небезопасный контент. Это полностью устранило человеческий фактор при редактировании баннера: если кто-то создаёт новый баннер с небезопасным контентом, он не сможет его показать в Почте, потому что он не сможет пометить его как безопасный. А если человек меняет старый баннер, который уже показывается в Почте, админка не даст сделать его небезопасным.

Повсеместный HTTPS

Далее нам пришлось поддержать HTTPS везде, где это возможно. Контента, который должен отдаваться по HTTPS, очень много, и он разнороден: это все картинки, статика, аватарки, аттачи. Одно дело — поддержать SSL на серверах, которые эти картинки отдают, другое дело — обеспечить корректность и протоколонезависимость ссылок (режим HTTPS является опциональным, поэтому ссылка должна быть правильной вне зависимости от того, является текущий протокол безопасным или нет). Соответственно, нам пришлось менять значительное количество не заточенных под это шаблонов. Мы работали полуавтоматическим способом: сначала через скрипты, потом всё зачищалось руками. Естественно, существенным изменениям подвергся тест-план: теперь наши тестировщики все это проверяют, правят, прогоняют автотесты и так далее.

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

Как это работает. Прокси получает HTTP-шный URL и получает по нему или контент, или редирект. Во втором случае прокси уходит по редиректам до какого-то значения, прописанного в конфиге. Если она в итоге получает HTTPS-редирект, она выдаёт его клиенту, то есть в браузер. Браузер показывает картинку оттуда напрямую. Если в конце выдаётся контент, то весь контент картинки мы стягиваем к себе, оборачиваем его в SSL и отдаём браузеру. Таким образом, все картинки показываются абсолютно безопасно, даже если они из небезопасного места. Отмечу, что мы сделали антибрутфорс и защиту от злоумышленного использования прокси.

Кроме того, нам пришлось перевести на SSL часть проекта Мой Мир, с которого Почта получает аватарки, а также серверы, на которых развернута система логирования. Также на SSL перешел Веб-Агент и серверы, с которых подгружаются аттачи и их превью.

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

В настоящий момент поддержка включена на iPhone и на iPad, у других мобильных устройств есть некоторые проблемы, над которыми мы работаем. Недалек тот час, когда на всех современных мобильных устройствах Почта Mail.Ru будет работать по умолчанию через HTTPS.

Оптимизация

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

Оптимизировали, как обычно, начиная с самых узких мест. Какое самое узкое место в SSL? Это коннект, потому что при коннекте происходит хендшейк. После установления хендшейка у клиента и сервера появляются некоторые данные, которые могут использоваться для шифрования и дешифрования в рамках именно этого соединения. Собственно, поскольку хендшейк очень дорогой, каждый коннект обходится системе недешево. Чтобы сократить число коннектов, мы выставили keepalive в 2 минуты (вместо одной секунды, как было ранее).

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

И напоследок расскажу о небольшом хаке, который тоже существенно увеличил производительность. Мы сделали линк с /dev/random на /dev/urandom. Работает быстрее, потому что /dev/random блокирующий, /dev/urandom не блокирующий. Следовательно, I/O wait сокращается. А поскольку на наших веб-серверах диски достаточно загружены (из-за логирования, приезжающей статики, сохранения атачей и т.д.), то дополнительный I/O wait оказывает существенное влияние на работу сервера в целом.

Заключение

SSL на крупном, высоконагруженном проекте с большим количеством компонентов связи— это действительно rocket science, и это не так просто, как кажется вначале. Это не просто разложить сертификаты. Это много-много таких вот маленьких, казалось бы, задач. Чем-то похоже на сбор паззла; различие в том, что единожды собранный паззл уже не разломается, а в нашем случае даже изменение одного компонента может привести к неожиданным последствиям. Поэтому важно выделять время и ресурсы на дополнительный мониторинг, проводить большое количество тестов, в том числе и автоматических, чтобы система продолжала радовать пользователя зеленым замочком безопасного соединения.

Если у вас остались вопросы по реализации HTTPS в условиях высоких нагрузок, задавайте их в комментариях, с удовольствием отвечу.

Денис Аникин,
технический директор Почты Mail.ru
Автор: @danikin

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

  • +1
    Расскажите плиз, какие ресурсы выделены под проксю, которая ходит по редиректам?
    Много ли запросов которые требуют более 1го редиректа?
    И какая нагрузка по запросам в секунду?
    • +1
      Около 10 серверов. Запросов с более чем одним редиректом мало, но они есть, к сожалению. А с одним редиректом (например, ссылка была с www редиректит на без www) — полно.
      Нагрузка порядка несколько тысяч rps на один сервер.
  • 0
    /dev/random => /dev/urandom… вы серьезно?

    Когда я последний раз проводил тестирование, большая часть браузеров поддерживала TLS Session tickets, гораздо большая чем те, что поддерживали SSL Sessions. Насколько сильно кеширование увеличило производительность?
    • 0
      Процентов на 20-30% ускорил.
      А трюк с рандомом — вообще чуть ли не в два раза дал эффект.
      • 0
        Неспроста, уровень энтропии в urandom намного ниже. Не боитесь за безопасность?
        • 0
          Это далеко не самое потенциально узкое место в безопасности. Про взлом SSL путем подбора рандомного числа я еще не слышал.
          • 0
            Не самое узкое, SSL как раз и взламывают из-за таких вещей. Это одно из самых уязвимых мест. Если атакующий сможет предсказать следующее случайное число — он может применить MITM.
            • +2
              Это правда. Но энтропии в urandom достаточно, чтобы нельзя было угодать следующее случайное число. Тот кто угадает, может не ломать нашу почту, а смело ехать в Монте-Карло.
              • 0
                Тем не менее, такие техники применяются.
      • 0
        На 20-30%, по сравнению с чем? Средним временем handshake у всех клиентов (включая session tickets и тех, кто вообще не поддерживает ни то, ни другое)?
        • 0
          Речь о среднем времени коннекта на сервер сайде (среди всех коннектов, и с поддержкой session tickets и без). По сравнению с отсутствием SSL-кэша.
          • 0
            Интересно! Видимо, играет роль специфика клиентов. На rackspace.com и нескольких других серверах, в основном, преобладали Session Tickets. Спасибо за ответ!
  • 0
    а как вы в баннерке проверяете безопасность flash содержимого? он же может подтягивать произвольные ресурсы? этот же вопрос касается и JS баннеров, которые могут по цепочке партнер->субпартнер->субпартнер подтягивать всякий раз разный код
    • 0
      Браузер не ругается на то, что флэш тянет что-то снаружи по небезопасному протоколу. А поскольку защищать, как вы сами понимаете, в рекламном баннере нечего (этот контент вообще никак не связан с пользователем), то проблемы, как таковой, нет.
      Внешние javascript'ы залить в нашу баннерную систему нельзя (грубо говоря, форма ввода для партнеров не позволяет их вводить). Поэтому мы можем автоматом проверять код и понимать, если в нем небезопасное содержимое.
  • 0
    а какой вообще выигрыш от введения SSL был? насколько уменьшилось количество жалоб на взломы ящиков? т.е. была ли какая то выгода от введения SSL кроме репутационных бонусов (в среде гиков знающих что такое SSL)?
    • 0
      Пока рано делать выводы. SSL в почте — это стратегическая задача. Вообще, проблема безопасности в Интертене — более менее общая и только одним сервисом целиком не решается. Если у пользователя одинаковый пароль от почты и от какой-либо соцсети, то ломают соцсеть — ломают и почту.
  • 0
    К огромному сожалению, SSL имеет очень запутанные настройки и много тонкостей в реализации. Шаг влево, шаг вправо — можно получить противоположный безопасности результат. При запуске SSL сервера обязательно нужно делать независимые проверки или хотя бы пользоваться сторонними сервисами тестирования.
    Если сейчас взглянуть на mail.ru через www.ssllabs.com/ssltest/analyze.html?d=mail.ru (Пример для одного из серверов в кластере: www.ssllabs.com/ssltest/analyze.html?d=mail%2eru&s=94%2e100%2e191%2e241 ) то можно увидеть несколько серьезных проблем:
    Разрешение использовать SSL v.2.0, подверженность атаке CRIME и атаке BEAST, DDoS атаке CVE-2009-3555

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

    Почему стоит обратить на это внимание — хотя CRIME и BEAST сложны в исполнении, но есть внутреннее ощущение, что низкая энтропия urandom делают возможность атаки более, чем вероятной.
    IMHO при такой нагрузке имеет смысл использовать аппаратный генератор случайных чисел — это сильно разгружает CPU и сохраняет высокий уровень энтропии.

    Почему стоит закрывать возможность для DDoS — говорить не стоит :)
    • 0
      Вы смотрите не на mail.ru, а на e.mail.ru: www.ssllabs.com/ssltest/analyze.html?d=e.mail.ru&s=94.100.184.17
      Почта отдается именно с домена e.mail.ru. А c mail.ru отдается главная страница, где https мы еще не анонсировали и только экспериментируем с ним.
      • 0
        В таком случае это плохое поле для экспериментов. Процесс Apache обслуживает как 80 так и 443 порт, который подвержен атаке CVE-2009-3555, в случае которой вы получите не работоспособность обоих протоколов.
        Пожалуйста, обратите этому моменту достаточное внимание.
        • +1
          У нас на главной странице нет apache. Там самописный сервер. Но за совет спасибо, внимание уже обратили!
  • +1
    Привет Денис,
    а вы не пробовали сравнить затраты на разработку, поддержку и сервера с покупкой готовых решений вроде F5?
    • 0
      Маг, привет.
      Смотря, о какой задаче идет речь. Если о поддержке https, то, как я написал в статье, проблема не в готовом или не готовом решении, а в том, что даже, если все решения уже есть (SSL поддержан везде, писать собственные алгоритмы шифрования не надо), то сделать так, чтобы все заработало на высоконагруженном проекте — это определенный челендж.
      • 0
        Да, я говорю именно про задачу отдачи контента через HTTPS на нагруженном проекте. Интересно было бы сравнить стоимость вашего решения с готовыми железками, которые делает например F5.
        Про то, что это челендж согласен :)
        • +2
          У меня на железки есть аллергия. Если программа рабоатет неправильно, то я ее пофикшу. А если железка работает неправильно, то ее только выкинуть и рвать волосы на голове)
  • +2
    И напоследок расскажу о небольшом хаке, который тоже существенно увеличил производительность. Мы сделали линк с /dev/random на /dev/urandom. Работает быстрее, потому что /dev/random блокирующий, /dev/urandom не блокирующий. Следовательно, I/O wait сокращается. А поскольку на наших веб-серверах диски достаточно загружены (из-за логирования, приезжающей статики, сохранения атачей и т.д.), то дополнительный I/O wait оказывает существенное влияние на работу сервера в целом.

    Денис, поясните, пожалуйста, как связанны ввод-вывод random/urandom и загруженные диски?
    • 0
      Алексей, связаны достаточно просто. Загруженные диски напрягают в целом всю подсистему ввода-вывода. И поэтому любая блокировка на файловом вводе выводе (даже не связанная с дисками, например чтение из /dev/random) может оставаться на больший срок, чем требуется для поступления данных.
      • +1
        жуть какая, и вы правда в это верите? чтобы перегрузить стек ввода-вывода надо сделать что-то невероятное, чтобы при этом упереться в процессор. Если вы хотите сломать мою картину мира, дайте пруф-линк пожалуйста, может это баг в ядре какой. Вобщем это заявление равносильно тому, что если я на высоконагруженном сервере по io вставлю флоппик и начну с него читать, производительность сервера упадет.
        • 0
          Если это будете обращаться к флоппи параллельно из 1000 потоков, то у вас все остальные io операции могут легко замедлиться. Но я сам флоппи вставлять в сервер не пробовал.
          А трюк с рандомом реально помогает.
          • 0
            > Если это будете обращаться к флоппи параллельно из 1000 потоков, то у вас все остальные io операции могут легко замедлиться.

            Из-за чего? в чем физика процесса? Может трюк с рандомом работает не из-за подсистемы ввода-вывода, а по каким-то другим причинам?
            • 0
              Я физику вам сходу не расскажу. По идее, io wait не должен влиять на поедание цпу, переключения контекстов не в счет, т.к. они случаются только при пробуждении. Но то, что много io wait'а тормозит весь сервер, это медицинский факт, который я наблюдаю за все свои 10 лет опыта работы с high load'ом.
              Если у вас есть другие более менее обоснованные гипотезы, то дайте их в студию, плиз.
              • 0
                Ну просто вы путаете вещи, тем самым еще и других запутываете. Да, при обращении к /dev/random процесс будет в uninterruptible sleep на ожидание ввода-вывода из него, да это увеличит показания iowait в системе, да, ваше приложение будет тормозить, потому что блокируются на чтении из /dev/random, но диски здесь совершенно не причем. Приложение которое работает с диском не будет при этом тормозить. Система — не будет тормозить. la в linux будет большим, но это говорит только о количестве процессов в uninterruptible sleep.
                • 0
                  Вы все верно говорите. Но это теория. На практике иначе.
                  • 0
                    Давайте пример, у меня другая практика почему-то. Меня, как инженера, любопытство разбирает, когда теория с практикой расходится, давайте разбираться, можно в личке. Это либо баг в ядре, либо какая-то странная особенность, которая может заафектить продакшн в самый неудобный момент.

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

Самое читаемое Разное