автор: Фадтрапонг Супакитудомкарн

Agoda предлагает более 200 вариантов оплаты, чтобы предоставить клиентам лучшие впечатления от путешествий. Мы используем .NET Core для создания платежных сервисов и связываемся с различными третьими сторонами для обработки платежей.

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

Как была настроена платежная система

Мы запускаем dotnet Core API, работающий в «контейнере» и размещаемый на различных серверах и в разных местах. Эти серверы полностью соответствуют стандартам индустрии платежных карт (PCI) и обеспечивают высокобезопасную среду — прямые внешние подключения к Интернету не допускаются.

Как мы подключаем наши услуги к Интернету? Вот тут-то и приходит на помощь наша команда по инфраструктуре. Они предоставляют то, что мы называем «прокси-URL». URL-адреса прокси действуют как безопасные шлюзы для доступа наших служб во внешний мир Интернета. Интересно то, что у нас есть несколько URL-адресов прокси-серверов для разных регионов.

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

Проблема

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

Для анализа сетевого подключения к третьей стороне мы выявили необходимость проанализировать различные события, происходящие внутри него. Нашей целью было определить событие, которое отняло больше всего времени. Для достижения этой цели. Сначала мы использовали команду tcpdump для перехвата всех исходящих пакетов, направленных на сторонний IP-адрес. Во-вторых, мы использовали аналитические данные о приложениях библиотеки dotnet, чтобы отслеживать, к каким внешним конечным точкам подключался наш платежный API, и измерять продолжительность каждого соединения. Такой подход позволил нам определить ключевые области для дальнейшего исследования.

Используя журналы, полученные из tcpdump и проанализированные с помощью Wireshark, мы обнаружили, что событие установления связи SSL между нашим контейнером и сторонним API занимало намного больше времени, чем должно было. Кроме того, анализ наших приложений выявил еще одну проблему. Нашим серверам требовалось 30 секунд, чтобы установить соединение с URL-адресом, которого мы никогда раньше не видели в нашем коде. Это была еще одна неожиданная задержка, которая привлекла наше внимание и, похоже, произошла одновременно с подключением к стороннему API.

При анализе данных tcpdump с помощью Wireshark связь с № 7 по № 8 заняла 30 секунд.

Прежде чем мы рассмотрим причину, по которой наши серверы подключаются к незнакомому URL-адресу, давайте кратко рассмотрим, как работают сертификаты SSL. Ниже приведен простой обзор, который даст вам общую картину.

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

Прежде чем сделать заказ, вы, вероятно, проверите звездный статус ресторана Мишлен на официальном сайте гида Мишлен. Аналогичным образом, ваш веб-браузер обращается к центру сертификации, чтобы подтвердить действительность SSL-сертификата веб-сайта. Эти шаги проверки имеют решающее значение для обеспечения высокого качества обслуживания, независимо от того, обедаете ли вы вне дома или просматриваете страницы в Интернете.

Теперь есть важный момент, который следует учитывать: точно так же, как ресторан может потерять звезду Мишлен, если он не будет соблюдать определенные стандарты, сертификат SSL может быть отозван, если веб-сайт станет небезопасным. В цифровой сфере существует так называемый список отзыва сертификатов (CRL), который отслеживает сертификаты, признанные недействительными.

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

Опираясь на аналогию со звездой Мишлен, рассмотрим дополнительные шаги, которые ваш браузер предпринимает для поддержания безопасного соединения с веб-сайтом. Точно так же, как вы проверяете звезду Мишлен в ресторане перед ужином, ваш браузер выполняет «проверку CRL» во время установления связи SSL, чтобы установить безопасное соединение HTTPS. Список отзыва сертификатов (CRL) содержит все сертификаты, которые были первоначально выданы, но впоследствии были отозваны по различным причинам, например, из-за подозрения на компрометацию или отсутствия необходимости в них.

Когда ваш браузер выполняет эту «проверку CRL», это похоже на то, что вы не ужинаете в ресторане, потерявшем звезду Мишлен. Если сертификат веб-сайта не указан в CRL, это похоже на то, что ресторан сохраняет свою звезду Мишлен, давая вам зеленый свет для безопасного и высококачественного обслуживания. Затем вы можете приступить к покупкам, просмотру или предоставлению конфиденциальной информации, будучи уверенным, что находитесь в безопасной и аутентичной среде.

Хорошие новости! Мы выяснили, что означает этот загадочный URL-адрес. Он был подключен к центру сертификации (CA) и требовал внешнего подключения к Интернету. Однако остается один нерешенный вопрос: почему этот процесс занял так много времени?

Итак, как мы это исправили?

Углубившись в проблему, мы обнаружили, что платежная система на нашем сервере пыталась установить прямое соединение с центром сертификации (CA), минуя прокси-сервер, предоставленный нашей инфраструктурной командой. Интересно, что у той же платежной системы, расположенной в другом регионе, подобных задержек не наблюдалось. Мы проконсультировались с нашей командой по инфраструктуре и узнали, что это несоответствие связано с конфигурацией нашей сети.

Мы сформулировали гипотезу для решения этой проблемы, работая в рамках существующей сети. Что, если мы обеспечим, чтобы все сторонние соединения направлялись через прокси? Помня об этой идее, мы экспериментировали с использованием Dotnet Core HttpClient на C#, чтобы проверить его осуществимость.

В коде нашей платежной системы мы уже установили прокси для подключения к конечной точке API. Это было сделано с помощью свойства Proxy из класса HttpClientHandler. Подробное объяснение вы можете найти на сайте документации Microsoft здесь.

Вот пример того, как мы настраиваем прокси в HttpClientHandler.

var handler = new HttpClientHandler();
handler.Proxy = new WebProxy(“http://agoda-proxy-server:port");
var client = new HttpClient(handler);

Во время проверок CRL HttpClient создаст отдельный экземпляр HttpClient для подключения к центру сертификации. Этот недавно созданный экземпляр HttpClient не наследует свойство Proxy от HttpClientHandler, используемого для основного HTTP-запроса. Таким образом, когда HttpClient взаимодействует с центром сертификации, он не использует прокси-сервер, который мы настроили в нашем HttpClientHandler.

Для получения более подробной информации посетите обсуждение этой проблемы GitHub.

Чтобы обеспечить маршрутизацию всех https-запросов через прокси-сервер, мы использовали свойство с именем DefaultProxy в классе HttpClient, который является частью платформы Dotnet Core. Более подробную информацию о DefaultProxy можно найти на веб-сайте документации Microsoft. Наша платежная система работает в контейнере на базе Linux. В этом контексте нам нужно было обновить переменную среды HTTPS_PROXY и назначить ей URL-адрес прокси-сервера.

Вот пример того, как можно настроить свойство DefaultProxy в скрипте bash платформы Unix.

export HTTPS_PROXY=http://proxy_server:port

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

Изучение альтернативного решения: обход проверок CRL

Альтернативный способ решения этой проблемы — отключить проверку CRL. Это можно сделать, настроив наш HTTP-клиент, в нашем случае свойство HttpClientHandler.CheckCertificateRevocationList property в .NET.

Вот как это можно реализовать на C#:

var handler = new HttpClientHandler();
handler.CheckCertificateRevocationList = false;
var client = new HttpClient(handler);

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

Заключение

Таким образом, мы успешно выявили и устранили проблему задержки в нашей платежной системе. Первоначально проблема была вызвана тем, что соединения CA SSL-подтверждения блокировались нашей сетью. Важно отметить, что это не часто встречающаяся проблема. Для тех, кто заинтересован в более глубоком понимании этой проблемы, дополнительную информацию можно найти в репозитории GitHub среды выполнения Dotnet.

Благодарности

Я искренне благодарен моим менеджерам Давиду Бояровичу и Хану Шруку за их неоценимые рекомендации и отзывы. Особая благодарность Джанет Джон за редактирование этого блога и моим коллегам из Agoda, которые помогали с обзорами.

Ссылки