Ssl pinning что это
Перейти к содержимому

Ssl pinning что это

  • автор:

Откручивание SSL пиннинга в Android приложениях

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

В наше время для взаимодействия компонентов веб-приложений используется протокол HTTPS, в основе которого лежат протоколы HTTP и TLS. Просто так перехватить трафик приложения не выйдет, т.к. он зашифрован. Можно, конечно, использовать прокси сервер, который с помощью своего сертификата сможет расшифровать трафик приложения и увидеть все запросы. Однако и средства защиты приложений не стоят на месте. Многие мобильные приложения используют SSL Pinning.

SSL Pinning – это внедрение SSL сертификата, который используется на сервере в код мобильного приложения. Таким образом, приложение не использует хранилище сертификатов устройства и не будет работать с сертификатом, который мы ему подсунули.

Ошибка, которая возникает в случае использования Burp suite для перехвата трафика с помощью собственного сертификата

Способы защиты приложений

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

Для данного способа необходимо добавить файл сертификата в файлы приложения, затем создать KeyStore и добавить в него наш сертификат.

После этого создаем сам TrustManager, который будет работать с нашим KeyStore, в котором находится нужный сертификат.

Далее создается SSLContext, который использует наш TrustManager. Затем указываем для URLConnection SocketFactory из созданного SSLContext.

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

Данная реализация работает непосредственно с API на достаточно низком уровне, поэтому этот способ надо использовать осторожно.

  • OkHttp CertificatePinner

Вторым способом является использование библиотеки OkHttp. В ней есть удобный CertificatePinner, который с помощью своего конструктора закрепляет за доменом определенный fingerprint сертификата.

Этот fingerprint высчитывается из сертификата, с которым должно работать приложение, а затем пишется непосредственно в код.

Можно указать несколько сертификатов для разных доменов.

  • Network Security Configuration

С версии Android 7.0 стала возможна настройка конфигурации сети. В папке res/xml/ создается файл network_security_config.xml, в котором прописываются правила и указываются fingerprints, как в случае с OkHttp.

Затем в AndroidManifest.xml прописывается использование данного файла в качестве android:networkSecurityConfig.

Этот способ позволяет редактировать сертификаты, не меняя исходный код приложения.

Способы обхода механизмов защиты

Frida – инструмент для динамического внедрения кода в приложение. Утилита прямо в процессе работы приложения способна отслеживать вызовы методов приложения, модифицировать методы приложения, обращаться к памяти выполняемого приложения и многое другое.

Для обхода SSL Pinning с помощью Frida есть несколько готовых скриптов, создающих кастомный TrustManager, который будет доверять нашему сертификату. Рассмотрим скрипт.

CertificateFactory и X509Certificate нужны для создания экземпляра сертификата из считанного файла.

FileInputStream и BufferedInputStream используются для считывания файла сертификата.

KeyStore – наш кастомный KeyStore, в который положим наш сертификат.

TrustManagerFactory создает экземпляр TrustManager, который будет работать с нашим KeyStore.

SSLcontext – реализация протокола SSL, которая выступает как factory для sslSocketFactory.

Считываем сертификат cert-der.crt, который мы предварительно поместили на устройство, и создаем экземпляр этого сертификата.

Создаем keyStore, в который складываем наш сертификат.

Создаем trustManager, который доверяет keyStore с нашим сертификатом.

Вот здесь начинается настоящее использование Frida. Данный фрагмент перезаписывает метод SSLContext. Теперь при вызове приложением метода сначала будет вызываться информационный лог в консоль, затем выполнится исходный метод, который мы перезаписываем. Но он вызовется не просто так. Вместо второго параметра, который будет передан в функцию, новая функция подставляет кастомный TrustManager с нашим сертификатом. И в конце снова информационный лог в консоль о том, что все прошло удачно.

Таким образом, данный скрипт готовит TrustManager, а затем использует его в методе вместо того, который передается (переменные a и с передаются в вызов исходной функции, а вот переменная b заменяется на кастомный TrustManager).

Frida позволяет переопределять методы, выполнять собственные скрипты. Поэтому с помощью Frida можно обойти защиту, реализованную через OkHttp CertificatePinner.

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

С другой стороны, для данного метода необходимо подключить телефон к устройству с Frida, установить frida-server на телефон, а это не всегда удобно.

  • Изменение исходного кода и пересборка apk

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

Для этого сначала нужно декомпилировать apk файл. Декомпилируется он в smali код. Smali – ассемблер для android-приложений. Все изменения будут производиться в .smali файлах, так как именно из них будет пересобираться приложение.

Для декомпиляции можно воспользоваться удобной утилитой apktool. Также для декомпиляции работы с разобранным apk, а затем и для сборки можно использовать удобное расширение для Visual Studio Code ApkLab.

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

ApkLab предоставляет также автоматизированный поиск необходимых участков кода. Рассмотрим что и почему он изменяет.

В первом файле утилита закомментировала исполнение следующих методов: checkClientTrusted, checkServerTrusted, getAcceptedIssuers.

По названиям методов можно предположить, что первый проверяет, является ли клиент доверенным, второй проверяет, является ли сервер доверенным, а третий получает лист доверенных сертификатов. Но не будем гадать и перейдем к Java-коду данных методов.

Теперь мы можем уже с пониманием рассмотреть, почему утилита закомментировала эти фрагменты. Первые два метода внутри ничем не отличаются и вызывают новый метод mo9499a (такое название из-за деобфускации), который слишком большой, чтобы вставлять его здесь. Но, судя по документации, этот метод строит цепочку сертификатов до корневого сертификата, а потом проверяет, можно ли ему доверять. В данном методе при ошибке будет выброшено исключение. Но мы закомментировали вызов данной функции, поэтому никаких проверок сертификат проходить не будет, и поэтому исключений мы не получим.

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

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

Также можно рассмотреть OkHttp CertificatePinner. В обзоре реализации был представлен фрагмент кода, где в OkHttpClient передается CertificatePinner. Найдя в smali соответствующий метод, можно убрать строчку, в которой CertificatePinner складывается в поле объекта OkHttpClient.

  • Изменение NSC (Network Security Configuration)

Самый простой способ обхода SSL Pinning.

В случае, если в приложении присутствует NSC, необходимо его изменить. В файле NSC могут быть прописаны base-config и domain-config.

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

В domain-config настраиваются домены.

Для обхода защиты достаточно лишь убрать весь блок .

ApkLab также умеет делать автоматическое изменение NSC файла.

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

  • Подмена файла сертификата

В случае, когда защита реализована с помощью TrustManager, использующего KeyStore, в котором лежит доверенный сертификат. Обычно KeyStore вшит в приложение. В .apk KeyStore обычно лежит либо в /res/raw, либо /assets.

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

Итог

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

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

Непосредственный патчинг apk хорош тем, что его можно сделать всего раз и на выходе будет приложение без SSL Pinning. Однако на этом пути может помешать защита приложения от пересборки. Конечно и ее можно попытаться обойти, раз мы имеем исходный код приложения, но это потребует больше времени и сил.

Изменение Network Security Configuration достаточно простой и рабочий способ, но редко когда приложения ограничиваются только этим способом защиты. Поэтому знание обхода этого способа SSL Pinning необходимо, но недостаточно.

Подмена KeyStore с доверенным сертификатом в файлах приложения тоже легко реализуется. Но опять же данный способ может не сработать в случае, если приложение при запуске проверяет, не было ли каких-либо изменений в файлах приложения (например, высчитывает чек-сумму).

Таблица 1. Область применения

Способ обхода

Способы защиты, которые можно обойти

TrustManager, OkHttp CertificatePinner

Что такое SSL pinning

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

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

Однако с использованием закрепления сертификата клиент добавляет дополнительный шаг для обеспечения соответствия сертификата сервера предопределенному или «закрепленному» сертификату или открытому ключу. Вместо полного доверия цепочке, клиент сравнивает предоставленный сертификат или открытый ключ с закрепленным значением, которое он хранит локально. Если они совпадают, соединение продолжается — в противном случае оно считается ненадежным.

SSL pinning предоставляет дополнительный уровень безопасности от атак, таких как атака «человек посередине» (MITM), когда злоумышленник перехватывает связь между клиентом и сервером и представляет поддельный сертификат для выдачи себя за сервер.

Атака MITM

Атака «человек посередине» (Man-in-the-Middle, MITM) — это вид атаки на безопасную связь, при которой злоумышленник встраивается между двумя участниками коммуникации и перехватывает их данные без их ведома. В контексте сертификата, атака MITM может происходить следующим образом:

  1. Когда клиент (например, мобильное приложение) пытается установить защищенное соединение с сервером, злоумышленник, находящийся между клиентом и сервером, подделывает себя за сервер и перехватывает запросы клиента.
  2. Злоумышленник создает собственный самоподписанный сертификат или использует сертификат от другого доверенного удостоверяющего центра, чтобы представиться клиенту в качестве сервера. Клиент, не имея механизма проверки подлинности сертификата, может поверить поддельному сертификату.
  3. Когда клиент отправляет данные, злоумышленник перехватывает их, имея возможность просмотреть, изменить или даже внедрить свои собственные данные в передаваемую информацию.
  4. Затем злоумышленник пересылает данные настоящему серверу, делая так, чтобы клиент и сервер не подозревали о наличии посредника.

Таким образом, атака MITM позволяет злоумышленнику просматривать и изменять коммуникацию между клиентом и сервером, нарушая конфиденциальность и целостность передаваемых данных.

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

Реализация SSL pinning

Закрепление может быть реализовано различными способами. Один из подходов — закрепление всего сертификата, включая всю цепочку доверия. Другой подход предполагает закрепление только открытого ключа сертификата, что может быть более гибким в случае необходимости серверу обновить свой сертификат, не затрагивая механизм закрепления.

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

Обход SSL pinning

Обход SSL pinning является сложной задачей и требует от хакера использования различных методов и техник. Вот несколько способов, которыми хакер может попытаться обойти меры защиты:

  1. Инструменты перехвата трафика: Хакер может использовать инструменты, такие как прокси-серверы, снифферы или промежуточное программное обеспечение, чтобы перехватывать и анализировать трафик между клиентом и сервером. Это позволяет хакеру просматривать и изменять передаваемые данные, обходя проверку.
  2. Декомпиляция приложения: Хакер может декомпилировать мобильное приложение и изучить его код и настройки. Это может позволить ему найти и обойти механизмы SSL pinning, изменить логику проверки сертификата или ключа, или даже удалить код, связанный с закреплением сертификата.
  3. Реверс-инжиниринг: Хакер может анализировать работу приложения или клиента и исследовать механизмы SSL pinning. Затем он может разработать методы для обхода этих механизмов, путем модификации приложения, внедрения кода или других техник, чтобы обойти проверку SSL pinning.
  4. Взлом устройства: Хакер может попытаться получить полный доступ к устройству клиента (например, мобильному телефону) путем использования вредоносного программного обеспечения, эксплойтов или других методов. Получив доступ к устройству, хакер может модифицировать операционную систему или конфигурацию, чтобы обойти механизмы SSL pinning.

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

Дополнительные статьи

  • Держи свой трафик в тайне. SSL Pinning — ещё раз о том же самом
  • SSL pinning во Flutter
  • Предотвращаем Man-in-the-Middle атаки в iOS с помощью SSL Pinning
  • Mastering SSL Pinning in Swift: No Third-Party Libraries Required
  • SSL Pinning in iOS
  • SSL Pinning in Android
  • 3 Ways How To Implement Certificate Pinning on Android

Держи свой трафик в тайне. SSL Pinning — ещё раз о том же самом

Меня зовут Юрий Шабалин, как вы, наверное, уже знаете, я один из основателей компании Стингрей Технолоджиз, разработчика платформы анализа защищенности мобильных приложений iOS и Android.

Сегодня я хотел бы снова затронуть тему безопасности сетевого взаимодействия между приложением и его серверной частью. На эту тему написано немало, но комплексной статьи, отвечающей на самые разные вопросы, начиная от того, что же такое SSL, до того, как работает атака MiTM и как от нее можно защититься, я еще не встречал (а может, просто плохо искал). В любом случае, мне бы хотелось поделиться своими мыслями на этот счет и внести свою малую долю в русскоязычный контент на эту тему. Статья может быть полезна разработчикам, которые хотят понять, как устроен процесс прикрепления (пиннинга) сертификатов и специалистам по анализу защищенности мобильных приложений.

Оглавление

  • Введение
  • Немного про протоколы
    • HTTP
    • HTTPS
      • Описание
      • Шифронаборы
      • TLS handshake (RSA)
      • TLS handshake (DHE/ECDHE)
      • Типы SSL Pinning
        • Certificate Pinning
        • Public key Pinning
        • Android Network Security Config
        • iOS App Transport Security
        • OkHttp
        • Retrofit
        • HttpUrlConnection
        • Volley

        Введение

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

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

        Немного про протоколы

        HTTP

        HTTP — широко распространённый протокол передачи данных, изначально предназначенный для передачи гипертекстовых документов (тех, которые могут содержать ссылки, позволяющие организовать переход к другим документам).

        Аббревиатура HTTP расшифровывается как HyperText Transfer Protocol, «протокол передачи гипертекста». В соответствии со спецификацией OSI, HTTP является протоколом прикладного (верхнего, 7-го) уровня. Последняя на данный момент версия протокола, HTTP/2, описана в спецификации RFC 7540. Также готовится к публикации третяя версия протокола (HTTP/3)

        Протокол HTTP предполагает использование клиент-серверной структуры передачи данных. Клиентское приложение формирует запрос и отправляет его на сервер, после чего серверное программное обеспечение его обрабатывает, формирует ответ и передаёт его обратно клиенту. После этого клиентское приложение может продолжить отправлять другие запросы, которые будут обработаны аналогичным образом.

        Задача, которая традиционно решается с помощью протокола HTTP — обмен данными между пользовательским приложением, осуществляющим доступ к веб-ресурсам (обычно это веб-браузер), и веб-сервером. На данный момент именно благодаря протоколу HTTP обеспечивается работа Всемирной паутины.

        API многих программных продуктов также подразумевает использование HTTP для передачи данных. Информация при этом может иметь любой формат, например, XML или JSON.

        Как правило, передача данных по протоколу HTTP осуществляется через TCP/IP-соединения. Серверное программное обеспечение при этом обычно использует TCP-порт 80, но могут быть задействованы и другие порты. Если порт не указан явно, то обычно клиентское программное обеспечение по умолчанию использует именно 80-й порт для открываемых HTTP-соединений.

        За описание протокола HTTP простыми словами спасибо вот этой статье.

        HTTPS

        Описание

        Как известно, протокол HTTP передает данные в открытом виде, то есть любой человек в сети может прослушать трафик и прочитать все сообщения, которыми обмениваются стороны. Для того, чтобы предотвратить возможность чтения и модификации запросов, поверх обычного HTTP добавили SSL и появился протокол HTTPS, где буква S расшифровывается как Secure, то есть безопасный. При HTTPS соединении все данные зашифровываются и расшифровать их могут только те, кому они предназначены (отправляющая и принимающая стороны). Реализовано это с применением SSL/TLS уровней защиты (Secure Sockets Layer / Transport Level Security). Давайте посмотрим, что это такое, и чем они отличаются друг от друга.

        История версий протоколов SSL/TLS

        SSL и TLS — это протоколы для защищенной передачи данных. TLS является прямым продолжением и, если можно так сказать, наследником SSL. Эти протоколы содержат в себе различные шифронаборы (Cipher Suites), которые можно использовать для осуществления операций шифрования, а также разнообразные правила коммуникации и многое другое. Первый протокол появился около 1995 года. От версии к версии он немного трансформировался: в него добавляли новые шифронаборы, убирали устаревшие, исправляли уязвимости и немного меняли сам протокол.

        Шифронаборы

        Что такое шифронаборы и почему они важны для нас?

        Шифронабор — это некоторая строка вида “ TLS_DH_RSA_WITH_AES_256_CBC_SHA256 ”, которая определяет, с использованием каких алгоритмов и по каким правилам будет осуществляться общение клиента и сервера. Давайте разберем по порядку, что за чем следует и что за что отвечает, — понимание этого потребуется нам в дальнейшем.

        • Protocol ( TLS ) – Протокол, по которому осуществляется соединение, а именно TLS или SSL.
        • Key Exchange ( DH ) – Алгоритм, по которому осуществляется обмен ключами. Это может быть RSA / DH (Диффи Хелман) / DHE (эфемерный Диффи Хелман) / ECDH (Диффи Хелман на эллиптических кривых) / ECDHE (эфемерный Диффи Хелман на эллиптических кривых) и другие. Чуть позже мы поймем, зачем я в обязательном порядке отметил эфемерные шифронаборы и дал каждому алгоритму расшифровку.
        • Authentication ( RSA ) – определяет, по какому алгоритму будет проходить аутентификация сторон (RSA / DSA / ECDSA / . )
        • Stream encryption ( AES_256_CBC ) — определяет, по каким протоколам будет осуществляться шифрование потока. При этом указывается длина ключа и режим (RC4_128 / AES_256_CBC / 3DES_EDE_CBC / . )
        • Message Authentication( SHA256 )— определяет, каким алгоритмом будет осуществляться подпись сообщений (MD5 / SHA / SHA256 / . )

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

        Даже некоторые регуляторы и мировые стандарты рекомендуют обращать пристальное внимание на используемую версию протокола и применяемые шифронаборы. Если обратиться к PCI DSS, то можно найти рекомендацию по обязательному отключению SSL/early TLS и использованию “Strong Cryptography“.

        Выдержка из PCI DSS

        При этом, включая только последние версии TLS с правильно настроенными шифронаборами, мы автоматически применяем свойство некоторых алгоритмов — Forward Secrecy (иногда Perfect FS). Его особенность в том, что компрометация сессионных ключей не происходит при компрометации одного из долговременных ключей. Работает эта опция только для эфемерных алгоритмов. То есть, речь идет про шифронаборы, начинающиеся с:

        TLS_DHE_* (EDH) Ephemeral DH

        TLS_ECDHE _* (EECDH) Ephemeral ECDH

        Для того, чтобы понять, что это значит и как работает, давайте сначала рассмотрим, как происходит осуществление защищенного соединения с обычными (не эфемерными) алгоритмами.

        TLS handshake (RSA)

        Схематично можно изобразить TLS-рукопожатие (процесс установки защищенного соединения) в виде следующей схемы:

        TLS-рукопожатие (RSA)

        Разберемся простыми словами, что при этом происходит:

        1. Чтобы соединиться с сервером, клиент отправляет ему некоторый Hello-запрос. Условно, он говорит: “Привет сервер, я хотел бы начать с тобой общение“.
        2. На сервере хранится пара ключей: приватный ключ (его никому нельзя передавать, раскрывать, и его компрометация ведет к самым печальным последствиям) и публичный ключ.
          В ответ на запрос клиента, сервер отправляет ему свой сертификат, в котором содержится его публичный ключ.
        3. Клиент на своей стороне вырабатывает предварительный секрет (большое случайное число), шифрует его на публичном ключе сервера, и этот зашифрованный секрет отправляет по сети серверу.
        4. Сервер, используя свой приватный ключ, расшифровывает предварительный секрет, и обе стороны независимо друг от друга вырабатывают Главный секрет, используя криптографическую магию.
        5. После того, как на обеих сторонах имеется одинаковый главный секрет, вырабатываются сеансовые ключи. На их основе уже и происходит шифрование данных. С этого момента защищенное соединение считается установленным и можно начинать передавать данные.

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

        TLS handshake (DHE/ECDHE)

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

        TLS-рукопожатие (DHE/ECDHE)

        И снова разберем, что происходит, и посмотрим на отличия:

        1. В первой части отличий никаких: клиент также отправляет запрос на подключение к серверу.
        2. Затем сервер так же возвращает клиенту свой публичный ключ из пары ключей вместе с сертификатом.
        3. А вот с этого момента применяются свойства эфемерных шифронаборов, а также немного криптографической магии. Вместо генерации предварительного секрета и его шифрования на публичном ключе, клиентская сторона вырабатывает свою пару ключей Диффи Хелмана, и открытый (публичный) ключ отправляет на сервер.
        4. Сервер на своей стороне также генерирует ключи с использованием эфемерного алгоритма и передает сгенерированный публичный ключ на сторону клиента.
        5. Вот тут происходит настоящая криптографическая магия, и на основе всей информации стороны независимо друг от друга могут сгенерировать Предварительный и Главный секреты.
        6. После этого на основе Главного секрета вырабатываются сеансовые ключи и начинается процесс передачи зашифрованных данных.

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

        Подведем итоги. При использовании TLS_DHE/ECDHE_* сессионный ключ не передается по сети. Общий секрет вырабатывается на основе DH с временными ключами, действительными только для текущей сессии.

        К слову, в iOS, при включенном и настроенном App Transport Security, приложение будет использовать PFS по умолчанию. Для детальной настройки реализована возможность управлять этой функцией с помощью ключа NSExceptionRequiresForwardSecrecy в plist файле. Выключение этого режима позволит использовать версии TLS, которые не поддерживают PFS.

        “Man In The Middle”, или “Человек посередине“

        Теперь, когда мы знаем, что такое HTTPS и как работает установка безопасного соединения, можно поговорить и о такой знаменитой атаке, как “Man In The Middle”. В русскоязычной литературе ее называют “Человек посередине“. Это атака на канал связи, при которой злоумышленник находится в одной сети с вами и обладает контролем над точкой доступа, или каким-то образом может перенаправить вас на свой прокси-сервер внутри сети. Злоумышленник для клиента представляется конечным сервером, а для сервера — клиентом. Он стоит “посередине“ между ними и способен читать и модифицировать трафик, проходящий через него. Но как это может быть реализовано? Ведь трафик зашифрован, и просто так прочитать его не получится. Проще всего это показать на небольшой схеме:

        Процесс атаки

        Если рассмотреть процесс подключения клиента (мобильного приложения) к своему серверу через подконтрольную точку доступа у злоумышленника, то он будет выглядеть так:

        1. Приложение обращается к своему серверу через точку доступа, подконтрольную злоумышленнику.
        2. На этой точке доступа развернут Proxy-сервер, через который проходит весь трафик.
        3. При запросе на соединение со своим сервером, Proxy “представляется” конечным адресатом, и в ответ на клиентский SSL-запрос возвращает свой собственный сертификат со своим публичным ключом.
        4. Клиент генерирует и зашифровывает предварительный секрет или генерирует пару ключей и обменивается ими с сервером злоумышленника, а не со своим.
        5. Таким образом, защищенное подключение устанавливается именно со “зловредным“ сервером и он, как принимающая сторона, видит весь трафик.
        6. С другой стороны, Proxy “представляется“ клиентом для целевого сервера и осуществляет с ним обмен данными, фактически, становясь “посредником“ между клиентом и сервером.

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

        Напомним еще раз, что сертификат – это электронный документ, который позволяет проверить аутентичность его предъявителя (пользователя, сервиса, системы). Он обычно содержит публичный ключ владельца, сводную информацию (имя владельца, срок действия и т.д.) и данные о том, кто именно издал этот сертификат.

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

        Давайте рассмотрим на практическом примере, как выглядит сертификат при осуществлении прямого соединения и соединения через Proxy. Для этого воспользуемся браузером и замечательным Proxy-сервером с практически неограниченным функционалом — Burp Suite.

        Для начала, откроем какой-нибудь сайт по протоколу HTTPS и посмотрим на сертификат, который он нам отдаст. Допустим, мы переходим по адресу https://stingray-mobile.ru/ :

        Сертификат сайта при подключении напрямую

        Мы видим, что сертификат имеет три шага, подписан промежуточным центром сертификации R3 (в свою очередь, подписанным корневым центром сертификации ISRG Root X1), выдан сроком на один год для доменного имени stingray-mobile.ru . Вместе с сертификатом к нам доставлен открытый ключ и его отпечаток. Обычно здесь содержится много информации: кому выдан, кем выдан, различные мета-данные самого сертификата и организаций, принимавших участие в его выдаче, и многое другое. Корневой центр сертификации ISRG Root X1 находится в списке доверенных внутри наших операционных систем. Это значит, что сертификаты, выданные данной компанией, валидные, и им можно доверять.

        Теперь откроем наш прокси Burp Suite и пустим трафик от браузера через него. Вот что мы увидим:

        Сертификат сайта при подключении через Proxy

        Изменилось абсолютно всё. Корневой центр сертификации теперь некий “PortSwigger CA“, организация, выпустившая сертификат, теперь тоже “PortSwigger“, изменился открытый ключ. Неизменным осталось только имя сервера — stingray-mobile.ru . При этом, мы полностью увидим все данные, которые мы отправили на сервер и которые получили от него:

        Дамп трафика в открытом виде

        Так как же это всё-таки работает? Внутри Proxy-сервера есть свой собственный сертификат, который выступает в роли корневого центра сертификации. Когда через прокси проходит обращение на какой-то адрес, прокси это понимает, “на лету“ выпускает сертификат именно для того домена, на который было обращение, подписывает его своим корневым сертификатом и отдает его клиенту. Клиент принимает сертификат с публичным ключом, проверяет, что доменные имена совпадают, и продолжает процедуру установки защищенного соединения.

        Чтобы вся эта схема работала, необходимо выполнение одного обязательного условия — на устройстве клиента должно быть безоговорочное доверие корневому центру сертификации от Proxy-сервера. Другими словами, пользователь должен согласиться и поставить на свой девайс некоторый сертификат и доверять ему. Кажется чем-то особенным, но на самом деле это происходит часто. Один из примеров — корпоративные устройства или корпоративные сети, для подключения к которым обязательно установить сертификат.

        Другой, более интересный способ заставить пользователя поставить нужный сертификат — прибегнуть к помощи фейковых точек доступа и Captive-порталов. С такими порталами вы наверняка сталкивались при попытке использовать какую-либо публичную сеть. Когда мы нажимаем “подключиться“, открывается страничка с просьбой, например, ввести свой номер телефона и проверочный код из СМС, или посмотреть рекламу, или что угодно еще.

        Как злоумышленник может использовать это для своих целей? Возможен такой сценарий: создается публичная точка доступа с популярным именем, например, METRO_FREE или что-то подобное. Далее, формируется Captive-портал с предупреждением о том, что “мы очень заботимся о вашей безопасности и хотим, чтобы вы всегда оставались защищенными”, ну и так далее. А в конце выводится кнопка, при нажатии на которую на подключившееся устройство скачивается сертификат и запускается мастер установки (для этого в запрос надо включить несколько специальных заголовков). Вот, собственно, и все — сертификат на устройстве, установлен, можно смотреть и слушать трафик!

        Другой важный вопрос: как заставить пользователей подключиться к фейковой точке доступа? Здесь на помощь приходят сами устройства и их способ определения, к какой точке и как подключаться. Выбор сети для подключения внутри телефонов очень прост: точка доступа идентифицируется по SSID (имени сети) и паролю. То есть, телефон видит сеть со знакомым именем и пытается подключиться к ней с сохраненным паролем (если установлен флаг “автоматическое подключение“). Но, если точка открытая и пароля на ней нет, то ее идентификация происходит только по имени сети. Но что делать, если рядом — две точки с одинаковым именем? Здесь главное, что нужно злоумышленнику, — подключиться к той точке, у которой сигнал выше. Для этого он может сделать следующее: купить направленную антенну, какой-нибудь одноплатник вроде raspberry, настроить Captive-портал, пойти в публичное место с открытым Wi-Fi, назвать свою точку доступа аналогично и ловить подключения! И тогда трафик клиентов, установивших сертификат на свой телефон, станет доступен тому самому “человеку посередине“.

        Похоже на сценарий какого-то фильма, далекий от реальности? А вот и нет. Однажды на одной конференции по безопасности в конце второго дня на сцену позвали участника и вручили ему приз — футболку, на которой были напечатаны адрес его электронной почты и пароль от неё. А на другом мероприятии на экран выводились логины и пароли, которые были пойманы в трафике (конечно, на второй день это заметили, и на экране стали выводить всякие неприличные рисунки в ASCII, и этот аттракцион прикрыли).

        А вот и не про конференции. Недавно я обедал в достаточно большом ресторане и подключился к местному Wi-Fi. В ожидании заказа решил проверить, что у них там по адресу маршрутизатора. И каково же было мое удивление, когда перейдя по адресу 192.168.88.1 , я попал в открытую админку роутера Mikrotik. Погуляв по настройкам, выяснил, что на нем не только развернута публичная точка доступа, но и подключено некоторое важное оборудование. А сколько таких вот открытых админок, наверное, только Shodan’у одному известно…

        Так что подобные схемы — это вполне реальная история, и попасть под сниффинг трафика можно достаточно просто (особенно если вы любите посещать конференции).

        Защита канала связи, или SSL Pinning

        В качестве защиты мобильного приложения от подобных атак применяют механизм, который называется SSL Pinning. По поводу него всегда много споров (делать ли его, нужен ли он, как избежать “протухания“ сертификата в приложении и т.д.). Для начала, стоит понять, для чего вашему приложению нужен SSL Pinning. Как правило, есть три типа ответа на этот вопрос:

        1. Для защиты клиента, если он вдруг попал в недоверенную/скомпрометированную сеть, если кто-то пытается прослушать его трафик и т.д.
        2. Для того, чтобы нельзя было проанализировать backend и поискать ошибки, например, в бизнес-логике (классический Security through obscurity)
        3. Для того, чтобы быть уверенными, что запрос приходит от легитимного приложения или, другими словами, для защиты от ботов.

        На мой взгляд, SSL Pinning призван решать одну единственную задачу — защищать клиента. По поводу двух оставшихся пунктов скажу кратко. Да, SSL Pinning может косвенно повлиять на них. То есть поможет и закрыть ваш API, и защитить от ботов (в теории), но это не серебряная пуля, а лишь способ обезопасить ваших клиентов.

        Для того, чтобы избежать копирования ваших приложений и защититься от ботов, лучше всего использовать альтернативные варианты реализации, а не пиннинг. Так, можно применять подпись сообщений, то есть генерировать некоторую уникальную строку, которая бы зависела от состава передаваемой информации в запросе и могла бы высчитываться независимо на клиенте (для подписания) и на сервере (для проверки). Такая подпись сообщений является некоторым аналогом цифровой подписи. Нечто подобное было реализовано у Snapchat и очень долго никто не мог понять, как же генерируется этот токен для подписания. На эту тему вышло даже две статьи (часть первая и часть вторая), где можно попробовать подсмотреть кое-какие подходы. А можно воспользоваться готовыми сервисами, которые есть, например, у Cloudfare, или аналогичными. И тогда никто и ничто, кроме вашего приложения, не сможет подключиться к бэкенду.

        А теперь немного о том, что же собственно такое SSL Pinning, как он устроен и как его применять. Суть этого метода в том, чтобы на этапе SSL Handshake после второго шага, когда сервер присылает нам свой сертификат с открытым ключом, приложение проверяло, что определенные параметры этого сертификата совпадают с тем, что ожидает получить приложение (то есть, некоторые данные, которые “зашиты“ в приложении и которые мы ожидаем получить от своего сервера). Схематично это можно представить в виде небольшой схемы:

        Процесс SSL Pinning

        Теперь посмотрим, что именно можно проверять и на каких этапах, и каким образом это можно реализовать.

        Типы SSL Pinning

        Certificate Pinning

        Первая реализация — это Certificate Pinning. Проверяется непосредственно сам сертификат, включая метаданные (кому он выдан, срок окончания, данные владельца и т.д.). Такая реализация наиболее безопасна, поскольку даже небольшое изменение в сертификате вызовет несоответствие и приведет к невозможности установить соединение.

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

        Public key Pinning

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

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

        Какие сертификаты возможно проверять

        1. Сертификат конечного сервера, с которым осуществляется соединение:
          1. Гарантирует с почти 100% уверенностью, что это ваш сертификат, даже если корневой центр был скомпрометирован;
          2. Если сертификат становится недействительным по какой-либо причине (либо по истечении срока действия, либо при компрометации), то осуществить соединение с сервером не получится, пока не выйдет обновление приложения;
          3. Позволяет использовать самоподписанные сертификаты, что может быть полезно при разработке.
          1. Проверяя промежуточный сертификат, вы доверяете промежуточному центру сертификации;
          2. Пока вы используете того же поставщика сертификатов, любые изменения сертификатов конечного сервера будут работать без обновления приложения.
          1. Проверка корневого сертификата означает, что вы доверяете корневому центру сертификации, а также любым посредникам, использующим данный центр сертификации;
          2. Если корневой сертификат скомпрометирован, то соединение нельзя считать защищенным, и необходимо срочно менять все сертификаты.
          1. Самая надежная проверка с точки зрения безопасности, поскольку проверяются все возможные изменения в любом из сертификатов;
          2. Это самая сложная проверка в поддержке, так как при изменении любого из сертификатов, участвующих в цепочке, необходимо обновлять приложение.

          Как правило, в большинстве случаев используют первый вариант и проверяют только сертификат конечного сервера, хотя встречаются реализации и посложнее.

          Еще одна интересная техника защиты клиента, которую мы встречали в процессе анализа приложений — это перекладывание ответственности на сторону сервера. Во время работы приложения отправляется запрос с частью сертификата (или с полным сертификатом), который приложение получило на этапе SSL Handshake, и сервер сам определяет, его ли это сертификат. На основе ответа от сервера мобильное приложение показывает пользователю сообщение, что он находится в небезопасной сети. Конечно, такое решение не должно быть единственным, но в качестве дополнительной проверки может пригодиться.

          Еще хочется рассказать об интересном наблюдении из практики, нередко сертификат, с которым будет сравниваться отпечаток сервера, хранится в виде файла на файловой системе (в директории или ресурсах приложения). Мы автоматизировали поиск таких ключей/сертификатов, а после того, как собрали неплохой результат, прогнав через сканер несколько сотен приложений, захотелось посмотреть, а что еще хранят приложения, какие сертификаты или файлы ключей?

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

          Такой подход позволяет контролировать появление нежелательных сертификатов в приложении, например, если по ошибке в сборку попадет приватный ключ (да, встречали и такое, когда по невнимательности в приложение попал ключ, который там ну никак не должен был быть):

          Найденное хранилище ключей с приватными ключами

          Как проверять

          Android Network Security Config

          Для каждой из возможных библиотек будет своя собственная реализация. Для Android, например, существует встроенный механизм реализации Pinning на уровне системы, а именно конфигурация сетевого взаимодействия (XML-файл, в котором настраиваются параметры сетевой безопасности). Данная настройка задается специальным атрибутом android:networkSecurityConfig в AndroidManifest.xml.

          Network Security Config позволяет достаточно просто подключить механизм Certificate Pinning в приложение. Но при этом стоит учитывать определенные нюансы. Рассмотрим конфигурацию, которая с первого взгляда выглядит, как правильно настроенная, и разберем, как ее можно немного улучшить:

            example.com 7HIpactkIAq2Y49orFOOQKurWxmmSFZhBCoQYcRhJ3Y=   

          Этот пример имеет два небольших недостатка:

          1. Для отпечатка сертификата (pin-set) не установлен срок действия;
          2. Нет резервного сертификата.

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

          Чтобы избежать такой паузы, стоит добавить следующий сертификат в настройках “резервных сертификатов“.

          Вот пример наиболее корректного использования функционала Certificate Pinning:

            example.com 7HIpactkIAq2Y49orFOOQKurWxmmSFZhBCoQYcRhJ3Y= fwza0LRMXouZHRC8Ei+4PyuldPDcf3UKgO/04cDM1oE=   

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

          iOS App Transport Security

          Что касается iOS, то встроенный механизм проверок в AppTransport Security появился только начиная с iOS 14 и очень похож на то, что есть в Android:

          NSAppTransportSecurity NSPinnedDomains example.org NSIncludesSubdomains NSPinnedCAIdentities  SPKI-SHA256-BASE64 r/mIkG3eEpVdm+u/ko/cwxzOMo1bk4TyHIlByibiA5E=     

          В этом примере конфигурации мы указываем, что отпечаток открытого ключа связан с доменом example.org и его поддоменами, например test.example.org . Но вот поддомены третьего уровня и выше уже в эту проверку не попадают (например notinclude.test.example.org ).

          Как и в Android, можно сразу же указать несколько отпечатков, что может быть полезно при ротации сертификатов на сервере:

          NSAppTransportSecurity NSPinnedDomains example.net NSPinnedLeafIdentities  SPKI-SHA256-BASE64 i9HaIScvf6T/skE3/A7QOq5n5cTYs8UHNOEFCnkguSI=  SPKI-SHA256-BASE64 i9HaIScvf6T/skE3/A7QOq5n5cTYs8UHNOEFCnkguSI=     

          Более подробно об этом механизме и о сертификатах в том числе, можно прочитать в моей статье, посвященной AppTransportSecurity.

          В нашем инструменте мы не только умеем выявлять отсутствие пиннинга, но и в обязательном порядке анализируем Network Security Config на предмет неправильной конфигурации и соответствия лучшим практикам безопасности:

          Пример найденной небезопасной конфигурации Network Security Config

          И, конечно, конфигурация App Transport Security не остается без внимания:

          Пример найденной небезопасной конфигурации App Transport Security

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

          OkHttp

          При реализации в OkHttp можно воспользоваться классом CertificatePinner.

          CertificatePinner certPinner = new CertificatePinner.Builder() .add("appmattus.com", "sha256/4hw5tz+scE+TW+mlai5YipDfFWn1dqvfLG+nU7tq1V8 https://medium.com/square-corner-blog/vulnerability-in-okhttps-certificate-pinner-2a7326ad073b#.kkns7f3jk">уязвимости, которая исправлена только в версии 2.7.5 и выше 3.2.0. Необходимо убедиться в том, что используемая версия библиотеки не подвержена данной уязвимости.

          Retrofit

          Retrofit применяется поверх OkHttp, поэтому его использование похоже на аналогичные операции с OkHttpClient, как показано в примере выше.

          Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://appmattus.com") .addConverterFactory(GsonConverterFactory.create()) .client(okHttpClient) .build();
          HttpUrlConnection

          Если используется HttpUrlConnection , рекомендуется пересмотреть подход в сторону OkHttp. Версия HttpUrlConnection , встроенная в Android, зафиксирована, поэтому с обновлениями могут возникнуть сложности.

          В документе Android «Security with HTTPS and SSL» предлагаемая реализация основана на pinning сертификатов с помощью собственного TrustManager и SSLSocketFactory . Однако, как и в случае с другими API, в данной рекомендации будут примеры с использованием SPKI.

          private void validatePinning( X509TrustManagerExtensions trustManagerExt, HttpsURLConnection conn, Set validPins) throws SSLException < String certChainMsg = ""; try < MessageDigest md = MessageDigest.getInstance("SHA-256"); ListtrustedChain = trustedChain(trustManagerExt, conn); for (X509Certificate cert : trustedChain) < byte[] publicKey = cert.getPublicKey().getEncoded(); md.update(publicKey, 0, publicKey.length); String pin = Base64.encodeToString(md.digest(), Base64.NO_WRAP); certChainMsg += " sha256/" + pin + " : " + cert.getSubjectDN().toString() + "\n"; if (validPins.contains(pin)) < return; >> > catch (NoSuchAlgorithmException e) < throw new SSLException(e); >throw new SSLPeerUnverifiedException("Certificate pinning " + "failure\n Peer certificate chain:\n" + certChainMsg); > private List trustedChain( X509TrustManagerExtensions trustManagerExt, HttpsURLConnection conn) throws SSLException < Certificate[] serverCerts = conn.getServerCertificates(); X509Certificate[] untrustedCerts = Arrays.copyOf(serverCerts, serverCerts.length, X509Certificate[].class); String host = conn.getURL().getHost(); try < return trustManagerExt.checkServerTrusted(untrustedCerts, "RSA", host); >catch (CertificateException e) < throw new SSLException(e); >>

          Данная имплементация должна быть вызвана следующим образом:

          TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance( TrustManagerFactory.getDefaultAlgorithm()); trustManagerFactory.init((KeyStore) null); // Find first X509TrustManager in the TrustManagerFactory X509TrustManager x509TrustManager = null; for (TrustManager trustManager : trustManagerFactory.getTrustManagers()) < if (trustManager instanceof X509TrustManager) < x509TrustManager = (X509TrustManager) trustManager; break; >> X509TrustManagerExtensions trustManagerExt = new X509TrustManagerExtensions(x509TrustManager); . URL url = new URL("https://www.appmattus.com/"); HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection(); urlConnection.connect(); Set validPins = Collections.singleton ("4hw5tz+scE+TW+mlai5YipDfFWn1dqvfLG+nU7tq1V8 anchor" name="Volley" >
          Volley

          Стандартный способ использования библиотеки Volley - это Pinning сертификатов, как описывается в статье «Android Security Tip: Public Key Pinning with Volley Library». Проект Github Public Key Pinning with Android Volley library показывает, как можно настраивать SSLSocketFactory для привязки к SPKI.

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

          Переопределить HostnameVerifier можно следующим образом:

          RequestQueue requestQueue = Volley.newRequestQueue(appContext, new HurlStack() < @Override protected HttpURLConnection createConnection(URL url) throws IOException < HttpURLConnection connection = super.createConnection(url); if (connection instanceof HttpsURLConnection) < HostnameVerifier delegate = urlConnection.getHostnameVerifier(); HostnameVerifier pinningVerifier = new PinningHostnameVerifier(delegate); urlConnection.setHostnameVerifier(pinningVerifier); >return connection; > >); . public static class PinningHostnameVerifier implements HostnameVerifier < private final HostnameVerifier delegate; private PinningHostnameVerifier(HostnameVerifier delegate) < this.delegate = delegate; >@Override public boolean verify(String host, SSLSession sslSession) < if (delegate.verify(host, sslSession)) < try < validatePinning(sslSession.getPeerCertificates(), host, validPins); return true; >catch (SSLException e) < throw new RuntimeException(e); >> return false; > >

          Но не стоит забывать, что SSL Pinning - это не единственное, что может помочь в защите сетевого соединения. Другим немаловажным фактором является создание правильного протокола общения приложения с сервером, например, запрет на общение в открытом виде по HTTP или запрет на передачу чувствительной информации в параметрах GET-запросов. О последней проблеме хотелось бы поговорить чуть более подробно.

          В случае, если чувствительная информация передается в URL-адресах, она может регистрироваться в самых разных местах, включая:

          • Web-сервер;
          • Любые прямые или обратные прокси-серверы между двумя конечными точками;
          • Заголовок Referrer;
          • Логи Web-сервера;
          • История браузера;
          • Кэш браузера.

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

          Найденный пароль, передаваемый в параметрах GET-запроса

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

          Обнаружение уязвимостей отсутствия или некорректной реализации SSL Pinning

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

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

          Выявленная уязвимость с указанием доменов, где был перехвачен трафик

          Заключение

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

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

          Ссылки

          1. Простым языком об HTTP
          2. Network security configuration
          3. A Security Analyst’s Guide to Network Security Configuration in Android P
          4. https://github.com/square/okhttp/wiki/HTTPS#certificate-pinning
          5. Vulnerability in OkHttp’s Certificate Pinner
          6. Picasso 2 OkHttp 3 Downloader
          7. Pinning
          8. Android Security Tip: Public Key Pinning with Volley Library
          9. Public Key Pinning with Android Volley library
          10. Preventing Downgrade Attacks
          11. Identity Pinning: How to configure server certificates for your app
          12. https://habr.com/ru/company/swordfish_security/blog/661345/
          13. HTTP/3
          • безопасность
          • безопасность мобильных приложений
          • mitm
          • ssl
          • tls
          • ssl pinning
          • perfect forward secrecy

          Что такое безопасность соединения или включите SSL-pinning в вашем мобильном приложении прямо сейчас

          В этой статье я кратко расскажу, что означает «безопасное соединение» между клиентом и сервером, что такое SSL-pinning, для чего он нужен и когда его использовать. Так же объясню от каких угроз мы защищаемся с его помощью.

          Безопасность соединения

          Представим, что у нас есть сайт или мобильное приложение (оба подпадают под определение клиента). При обращении сайта или мобильного приложения к бекенду (сервер) безопасность соединения обеспечивается с помощью протокола SSL (Secure Socket Layer), а если быть точнее, TLS (Transport Layer Security). TLS ставит своей целью создание между двумя узлами сети защищённого от прослушивания и подмены информации канала связи, а также проверку того, что обмен данными происходит между именно теми узлами, т.е. обеспечение конфиденциальности, целостности и аутентификации. Под узлами можно понимать сервер и мобильное приложение, либо сервер и веб-браузер.

          Немного истории про SSL/TLS

          Изначально SSL был разработан компанией Netscape для своего одноименного браузера в середине 90-х. Позднее на основании SSL 3.0 был принят RFC-стандарт TLS 1.0. Рекомендованными для применения в 2019 году являются версии TLS не ниже 1.2 (актуальная версия на сегодня — 1.3). На странице в википедии можно посмотреть поддержку версии TLS у всех популярных браузеров.

          Человек посередине

          MITM (Man in the middle) — данный вид атаки направлен на «прослушку» или изменение трафика между двумя узлами (клиентом и сервером). В случае использования незащищенного HTTP это не составляет труда, тогда как в случае HTTPS (HTTP + SSL, или HTTP secure) данные зашифрованы и обычный просмотр пакетов трафика не даст никакой полезной информации злоумышленникам об их содержании. О том, каким образом шифруются данные, поговорим дальше.

          Симметричное, ассиметричное шифрование

          Симметричное шифрование — вид шифрования, при котором для шифрования и дешифрования будет использоваться один и тот же ключ. Наиболее стойким на данный момент является шифр AES (Advanced Encryption Standard), длина ключа может быть 128, 192 или 256 бит. Из минусов симметричного шифрования — проблема передача ключа, ведь в случае его утери, им может воспользоваться злоумышленник. В случае TLS используется ассиметричное шифрование — когда для шифрования используется публичный ключ, а для дешифрования приватный. Публичный ключ передаётся от узла 1 к узлу 2, и даже в случае его перехвата злоумышленником, содержимое данных невозможно расшифровать, т.к. закрытый ключ не передается между узлами. Наиболее распространённый шифр этого типа — RSA (Rivest — Shamir — Adleman), размер ключа от 1024 до 4096 бит. Удобство ассиметричных шифров так же в том, что публичный ключ может быть передан большому количеству узлов без угрозы его утечки, как в случае ключа симметричного шифра. Из минусов — асимметричные шифры значительно медленнее симметричных. Поэтому в TLS используется смешанный подход — все данные шифруются симметрично, а набор ключей асимметрично. Но так как узлы шлют информацию в обе стороны, необходимо шифровать трафик с двух сторон. На помощь приходит протокол Диффи-Хеллмана. Первые 2 минуты видео достаточно понятно объясняют принцип его работы. Если мы хотим защитить соединение по HTTP, здесь стоит подумать о SSL-сертификате.

          Сертификат X.509

          В качестве удостоверяющего хост документа выступает сертификат стандарта X.509. Под сертификатом можно понимать файл, в котором содержится следующая информация:

          • Название
          • Публичный ключ
          • Серийный номер
          • Алгоритм сертификата
          • Цифровая подпись и др.

          При нажатии на иконку замка в строке сайта

          Сертификаты не существую сами по себе — их выпускают центры сертификации (Certificate Authority), в цепочке сертификатов самым первым является сертификат CA, его еще называют корневой. CA являются общеизвестными и ключи, которые они выпускают являются доверенными по умолчанию. Корневые сертификаты как правило “зашиваются” в операционную систему и обновляются при следующих обновлениях. Сертификаты выстраиваются в цепочку, можно так же назвать термин дерево: сертификаты первого уровня (выпущенные CA), так же могут выпускать сертификаты следующих уровней. В случае компрометации сертификата, он может быть отозван, и тогда автоматически отзываются все дочерние сертификаты.

          Человек посередине по TLS

          Кажется, что TLS решает атаку MITM. Тем не менее, возможен вариант, когда между узлами окажется самоподписанный корневой сертификат злоумышленника и каким-то образом этот сертификат попадёт к нам на устройство. Например, если пользователь недостаточно технически образован и ему предлагается установить сертификат для пользования сетью Wi-Fi. После этого данные шифруются сертификатом злоумышленника (которые он легко расшифровывает) и мы не подозреваем о подмене. В данном случае злоумышленник выступает неким прокси-сервером между нашими узлами.

          SSL-pinning

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

          Схема работы SSL-pinning​

          Как проверять сертификат или виды SSL-pinning

          По тому, какой сертификат проверяем:

          • Цепочка сертификатов — можно проверять данные каждого из сертификатов в цепочке.
          • Конечный сертификат — наиболее распространённый вариант на практике, проверяется сертификат самого нижнего уровня.
          • Корневой или промежуточный сертификат. Например, несколько наших хостов имеют один родительский сертификат, можем проверять только его вместо нескольких проверок.

          По тому, какие данные из сертификата проверяем:

          • Фингерпринт. Это хэш от данных сертификата (можно выбрать, например из SHA-1, SHA-256). Фингерпринт видно в окне браузера при просмотре сертификата. Подход достаточно прост в реализации и обычно в SDK уже есть API по вычислению фингерпринта сертификата. Но к минусам такого подхода могу отнести то, что при истечении сертификата прежний фингерпринт становится невалидным, и его необходимо обновить на клиенте. Невалидным он становится, т.к. у нового сертификата как минимум будет новый приватный ключ.
          • Публичный ключ. Данный вид лишён недостатка о перевыпуске сертификата, т.к. если в вашем распоряжении имеется прежний сертификат (пара публичный-приватный ключ), то вы сможете выпустить новый сертификат с тем же публичным ключом даже у другого CA. После истечения текущего не придётся обновлять информацию на клиенте. К недостаткам можно отнести, во-первых, что публичный ключ извлекается чуть сложнее, чем фингерпринт, и во-вторых, сам по себе факт того, что ключ не будет меняется долгое время.

          Фингерпринт виден в том же окне просмотра сертификата в Safari​

          Когда SSL-pinning не нужен

          • Хосты сторонних сервисов — сертификат может измениться без нашего ведома. Например, Google-аналитика.
          • Нет чувствительных данных — нет никакой угрозы, что данные будут получены третьей стороной. Например, любые открытые сервисы (текущее время, погода).

          Вместо вывода

          Раз уж мы обсудили SSL-pinning в контексте мобильных приложений, почему бы не сделать тоже самое с веб-сайтами? Ответ достаточно прост — браузер посещает большое количество сайтов, ровно как и каждый день появляется много новых, и это достаточно проблематично обладать информацией обо всех них. Мобильное приложение же, как правило, обращается к конечному числу доменов, информация о сертификатах хранится внутри него. В 99% случаев не нужно придумывать свои способы шифрования, TLS + SSL-pinning обеспечивают достаточный высокий уровень безопасности для передачи чувствительных данных по сети. Примеры приложений, где SSL-pinning является по-моему мнению обязательным — это мобильные приложения банков, другие приложения из финансового и страхового сектора. Для более подробного погружения в схему работы TLS советую данный ресурс.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *