Большинство приложений React Native, созданных сегодня, будут подключены к серверной части для удаленного доступа к информации. Но знаете ли вы, как лучше всего защититься от злонамеренных попыток взломать данные ваших пользователей? Давайте покажем вам, как может помочь закрепление SSL.

командой Whitespectre React Native

Соавторы этой статьи — Джефферсон Таварес де Падуа и Мохамед Шараф, члены команды Whitespectre React Native.

Если вы разработчик в современном высоко взаимосвязанном мире, скорее всего, вы создали приложение, которое использует данные из API, чтобы позволить пользователям иметь доступ к своему контенту независимо от того, где они находятся, верно? Но задумывались ли вы когда-нибудь о том, что эти данные может получить кто-то еще, а не только ваш конечный пользователь?

Да, это на самом деле возможно, и если вы удивлены, скорее всего, кто-то это делает. Но не больше! В этой статье мы покажем вам, как добавить дополнительный уровень безопасности в приложение React Native, а также как протестировать его, чтобы убедиться, что все работает должным образом. Взволнованный? Тогда давайте углубимся в это.

Что я могу сделать, чтобы защитить свои данные?

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

Но я использую HTTPS для связи с сервером, — говорит разработчик.

Что ж, HTTPS действительно может помочь предотвратить доступ злоумышленника к содержимому запроса, когда он передается с сервера клиенту, но он не мешает злоумышленнику, взломавшему устройство пользователя, фактически прочитать содержимое запроса. запросы.

Это означает, что даже если вы используете HTTPS, если кто-то установит, скажем, прокси-сервер между телефоном вашего пользователя и вашим сервером, он все равно сможет читать данные вашего сервера, и, конечно, мы хотим предотвратить это. Вот тут-то и вступает в игру SSL-пиннинг, потому что, как только ваше приложение будет прикреплено к сертификату вашего сервера, если кто-то попытается проникнуть в середину соединения, чтобы прочитать эти запросы, связь немедленно прекратится, поэтому злоумышленник не будет возможность отслеживать содержимое вашего приложения.

Как реализовать закрепление SSL в React Native?

Теперь, когда вы понимаете, что SSL Pinning может добавить к вашему приложению, вы, вероятно, задаетесь вопросом, как реализовать это в своем приложении, верно? Что ж, если вы выполните поиск в Google по этой теме (вероятно, именно так вы и оказались здесь), одним из лучших результатов будет библиотека под названием react-native-ssl-pinning, которую можно использовать для достижения поведение, которое мы только что описали. Но подождите, пока не закрывайте вкладку, потому что эта библиотека работает поверх метода выборки, доступного в React Native, и если у вас есть приложение, которое уже используется людьми, скорее всего, вы, вероятно, использование другого клиента для отправки запросов на отправку (например, axios), и эта библиотека не позволяет переключиться с fetch на другой клиент.

Есть также несколько других библиотек, которые пытаются решить эту же проблему, но у них есть свои проблемы, и большинство из них не имеют достаточной поддержки, чтобы их можно было рассматривать в качестве альтернативы для реального приложения. С учетом сказанного, если вы не запускаете приложение с нуля и fetch не может удовлетворить все ваши потребности, лучшим решением будет добавление закрепления SSL изначально на платформах, на которых будет использоваться ваше приложение, чтобы каждый раз, когда запрос отправляется на уровне JS, базовая собственная реализация сети, которая выполняется на Android/iOS, использует закрепление SSL.

Получение открытых ключей

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

openssl s_client -showcerts -servername YOUR_DOMAIN.COM -connect YOUR_DOMAIN.COM:443

Эта команда выведет все доступные сертификаты, поэтому теперь вам нужно сохранить их, чтобы мы могли использовать их позже. Сертификат начинается с -----BEGIN CERTIFICATE----- (префикс) и заканчивается -----END CERTIFICATE----- (суффикс), вам необходимо скопировать все содержимое (включая префикс и суффикс) и сохранить в отдельный файл с расширением .pem. Сделайте это для всех доступных сертификатов (и, конечно, создайте файл для каждого из них).

Как только это будет сделано, на шаге 2 мы преобразуем сертификаты, полученные на шаге 1, в base64, чтобы использовать их в нашем коде. Для этого просто запустите приведенную ниже команду и скопируйте вывод, который будет использоваться позже.

openssl x509 -in PATH_TO_YOUR_CERTIFICATE.pem -pubkey -noout | openssl rsa -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64

Конкретная реализация Android

Теперь, когда у нас есть сертификаты, пришло время использовать их в нашем коде. Давайте сначала посмотрим, как настроить его на Android. Базовой сетевой реализацией React Native на Android по умолчанию является библиотека OkHttp, которая предоставляет нам способ использовать закрепление SSL путем создания класса, реализующего интерфейс OkHttpClientFactory.

Главный вывод здесь заключается в том, что если вы хотите, чтобы все ваши поддомены также были закреплены (рекомендуется), вы можете сделать это, включив **. на ваше имя хоста. Также не забудьте вызвать .add в _CertificatePinner.Builder()_ для каждого из ключей, которые вы закодировали в base64 на шаге 2. Теперь нам просто нужно включить этот класс в наш стек вызовов (это нужно сделать как одну из первых вещей внутри ваш MainActivity), мы можем сделать это, позвонив:

OkHttpClientProvider.setOkHttpClientFactory(new CertificatePinningFactory());

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

Еще одна вещь, о которой следует помнить, это то, что если у вас есть файл network_security_config.xml в вашем проекте, убедитесь, что у вас нет <certificates src="user" /> внутри вашего домена в том варианте, в котором вы хотите, чтобы закрепление SSL было включено, иначе пользователь будет иметь возможность переопределить закрепленный сертификат (что в значительной степени убивает всю работу, которую мы здесь проделали).

Конкретная реализация iOS

Для iOS реализация также проста, и мы будем использовать библиотеку под названием Trustkit, которая позволяет нам закреплять запросы, происходящие на нативном уровне iOS. Чтобы использовать Trustkit, вам сначала нужно включить его в проект, поэтому откройте свой подфайл и добавьте pod 'TrustKit' внутри целей, которые вы хотите использовать прикрепление SSL.

Как только это будет сделано, перейдите к файлу AppDelegate.m и добавьте приведенный ниже код и не забудьте включить все ключи, полученные на шаге 2, в массив kTSKPublicKeyHashes.

Реализация здесь относительно аналогична реализации Android, так что следите за:

  • kTSKIncludeSubdomains и измените значение между @YES или @NO, если хотите/не хотите, чтобы ваши поддомены были закреплены,
  • kTSKEnforcePinning, который полностью отклонит все запросы, если домен не будет должным образом проверен (рекомендуется)

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

Как проверить, что закрепление SSL работает в разных средах тестирования?

Существует несколько инструментов, используемых в основном для перехвата вызовов API, сделанных с мобильных устройств, к их целевым конечным точкам, и ниже приведены наиболее распространенные:

  • Проксиман
  • Burp Suite Сообщество
  • Чарльз Прокси

Ниже мы рассмотрим настройку прокси-серверов для proxyman и burp suite, поскольку прокси-сервер charles очень похож на proxyman.

1. Проксимен (доступно только на macOS)

Настройте сертификат ЦС на iOS

  • На вашем макбуке откройте proxyman
  • В настройках Wi-Fi iOS переключите настройки прокси на ручной
  • Укажите на сервер <macbook local IP> «Обычно это что-то вроде 192.168.1.104»
  • Укажите на порт 9090 и аутентификация не требуется
  • В Safari откройте http://proxy.man/ssl
  • Установите необходимый сертификат под названием «Proxyman CA».

  • Теперь вы готовы начать перехватывать и просматривать запросы API, сделанные всеми приложениями на мобильном устройстве.
  • Проверка запросов на proxyman может быть такой же простой, как просмотр различных приложений на вашем мобильном устройстве.
  • Любой запрос, сделанный из приложения, будет отображаться в прокси-менеджере, классифицированном по целевому URL-адресу. например: открытие www.apple.com в любом из браузеров.

  • Это должно сгенерировать запрос GET к URL-адресу
  • Чтобы расшифровать шифрование SSL, щелкните правой кнопкой мыши URL-адрес слева и выберите «Включить прокси SSL».

  • После того, как вы выберете этот вариант, если закрепление SSL работает нормально, все запросы к конечным точкам должны завершиться ошибкой.

  • Ниже приведены пункты, которые необходимо проверить при тестировании функции закрепления SSL:
  • Все запросы к конечной точке должны завершиться ошибкой, пока активно закрепление SSL.
  • Все содержимое запроса должно быть скрыто (тело + заголовки)
  • Ответ не должен отображаться

2. Сообщество Burp Suite

Настройте сертификат ЦС на iOS

  • В пакете Burp перейдите на вкладку прокси.
  • Нажмите кнопку «Добавить» и добавьте текущий локальный IP-адрес и порт 9090.

  • В настройках Wi-Fi iOS переключите настройки прокси на ручной
  • Укажите на сервер <macbook local IP> «Обычно это что-то вроде 192.168.1.104»
  • Укажите на порт 9090 и аутентификация не требуется
  • В Safari откройте http://burpsuite и установите необходимый сертификат Portswigger CA.

  • Теперь вы готовы начать перехватывать и просматривать запросы API, сделанные всеми приложениями на мобильном устройстве.
  • Проксирование SSL в Burp включено по умолчанию, поэтому нет необходимости выполнять какие-либо дополнительные действия. Просто включите сертификат в Общие настройки iOS › О программе › Настройки доверия сертификата
  • Проверка запросов на burp выполняется следующим образом:

  • В burp, поскольку проксирование SSL включено по умолчанию, любой неудачный запрос не должен отображаться, а приложения, имеющие защиту SSL Pinning, не должны работать или быть способными выполнять какие-либо запросы к серверной части.

Остерегайтесь, когда вы включаете закрепление SSL в свое приложение

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

Не забудьте поставить 👏🏻, если вам нравится читать наши статьи!

И подпишитесь на наши истории, чтобы первыми узнавать, о чем мы говорим 💡